diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h index 5d1bc89e2d9ee5f1fe303eb7856842e56d37252a..fd4d706b57cc20bcdd20ffbba8bd756a28c8b8b0 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h @@ -38,15 +38,16 @@ public: size_t maxScatterPtAttempts); std::tuple<double, double> calculate(Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &finalPos, - double lambdaBefore, double lambdaAfter, - std::string &debugString) const; + double lambdaBefore, double lambdaAfter); + std::string getDebugString() const { return debugString; }; private: const IBeamProfile &m_beamProfile; - const MCInteractionVolume m_scatterVol; + MCInteractionVolume m_scatterVol; const size_t m_nevents; const size_t m_maxScatterAttempts; const double m_error; + std::string debugString; }; } // namespace Algorithms diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h index a93d3ad1b61e896328c509f2f572f5b5cdaae3d0..80eac35fec68ae51beccc44ac59c717452e063e7 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h @@ -9,6 +9,7 @@ #include "MantidAlgorithms/DllConfig.h" #include "MantidGeometry/Objects/BoundingBox.h" +#include <boost/optional.hpp> namespace Mantid { namespace API { @@ -45,13 +46,18 @@ public: double calculateAbsorption(Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &startPos, const Kernel::V3D &endPos, double lambdaBefore, - double lambdaAfter) const; + double lambdaAfter); std::string generateScatterPointStats() const; - Kernel::V3D generatePoint(Kernel::PseudoRandomNumberGenerator &rng) const; + Kernel::V3D generatePoint(Kernel::PseudoRandomNumberGenerator &rng); private: - mutable int m_sampleScatterPoints = 0; - mutable std::vector<int> m_envScatterPoints; + int getComponentIndex(Kernel::PseudoRandomNumberGenerator &rng); + boost::optional<Kernel::V3D> + generatePointInObjectByIndex(int componentIndex, + Kernel::PseudoRandomNumberGenerator &rng); + void UpdateScatterPointCounts(int componentIndex); + int m_sampleScatterPoints = 0; + std::vector<int> m_envScatterPoints; const boost::shared_ptr<Geometry::IObject> m_sample; const Geometry::SampleEnvironment *m_env; const Geometry::BoundingBox m_activeRegion; diff --git a/Framework/Algorithms/src/MonteCarloAbsorption.cpp b/Framework/Algorithms/src/MonteCarloAbsorption.cpp index ea990c3c901d05507d30311f9dd08d143fbc98a3..83d75020a49f8faa55b558ac45e8976d9329ab50 100644 --- a/Framework/Algorithms/src/MonteCarloAbsorption.cpp +++ b/Framework/Algorithms/src/MonteCarloAbsorption.cpp @@ -276,10 +276,10 @@ MatrixWorkspace_uptr MonteCarloAbsorption::doSimulation( } else { // elastic case already initialized } - std::string debugString; + std::tie(outY[j], std::ignore) = - strategy.calculate(rng, detPos, lambdaIn, lambdaOut, debugString); - g_log.debug(debugString); + strategy.calculate(rng, detPos, lambdaIn, lambdaOut); + g_log.debug(strategy.getDebugString()); // Ensure we have the last point for the interpolation if (lambdaStepSize > 1 && j + lambdaStepSize >= nbins && j + 1 != nbins) { diff --git a/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp b/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp index 8858f1e9b69138eed602faca4fb61c5c5ca50ad0..40f44015131013c079580976a61e7890a63ff8a4 100644 --- a/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp +++ b/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp @@ -43,12 +43,12 @@ MCAbsorptionStrategy::MCAbsorptionStrategy(const IBeamProfile &beamProfile, * where it is detected * @param lambdaBefore Wavelength, in \f$\\A^-1\f$, before scattering * @param lambdaAfter Wavelength, in \f$\\A^-1\f$, after scattering - * @param debugString string to return any debug messages * @return A tuple of the <correction factor, associated error>. */ -std::tuple<double, double> MCAbsorptionStrategy::calculate( - Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &finalPos, - double lambdaBefore, double lambdaAfter, std::string &debugString) const { +std::tuple<double, double> +MCAbsorptionStrategy::calculate(Kernel::PseudoRandomNumberGenerator &rng, + const Kernel::V3D &finalPos, + double lambdaBefore, double lambdaAfter) { const auto scatterBounds = m_scatterVol.getBoundingBox(); double factor(0.0); for (size_t i = 0; i < m_nevents; ++i) { diff --git a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp index 62d8c874eb0a34540b95291935d4aae62eaa9dda..cc85412265e28cfcfe7b25a650c241f2c0f9a4e5 100644 --- a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp +++ b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp @@ -40,6 +40,7 @@ MCInteractionVolume::MCInteractionVolume( } try { m_env = &sample.getEnvironment(); + assert(m_env); if (m_env->nelements() == 0) { throw std::invalid_argument( "MCInteractionVolume() - Sample enviroment has zero components."); @@ -61,6 +62,58 @@ const Geometry::BoundingBox &MCInteractionVolume::getBoundingBox() const { return m_sample->getBoundingBox(); } +/** + * Randomly select a component across the sample/environment + * @param rng A reference to a PseudoRandomNumberGenerator where + * nextValue should return a flat random number between 0.0 & 1.0 + * @return The randomly selected component index + */ +int MCInteractionVolume::getComponentIndex( + Kernel::PseudoRandomNumberGenerator &rng) { + int componentIndex; + // the sample has componentIndex -1, env components are number 0 upwards + if (m_env) { + componentIndex = rng.nextInt(0, static_cast<int>(m_env->nelements())) - 1; + } else { + componentIndex = -1; + } + return componentIndex; +} + +/** + * Generate a point in an object identified by an index + * @param componentIndex Index of the sample/environment component where + * the sample is -1 + * @param rng A reference to a PseudoRandomNumberGenerator where + * nextValue should return a flat random number between 0.0 & 1.0 + * @return The generated point + */ + +boost::optional<Kernel::V3D> MCInteractionVolume::generatePointInObjectByIndex( + int componentIndex, Kernel::PseudoRandomNumberGenerator &rng) { + boost::optional<Kernel::V3D> pointGenerated; + if (componentIndex == -1) { + pointGenerated = m_sample->generatePointInObject(rng, m_activeRegion, 1); + } else { + pointGenerated = m_env->getComponent(componentIndex) + .generatePointInObject(rng, m_activeRegion, 1); + } + return pointGenerated; +} + +/** + * Update the scatter point counts + * @param componentIndex Index of the sample/environment component where + * the sample is -1 + */ +void MCInteractionVolume::UpdateScatterPointCounts(int componentIndex) { + if (componentIndex == -1) { + m_sampleScatterPoints++; + } else { + m_envScatterPoints[componentIndex]++; + } +} + /** * Generate point randomly across one of the components of the environment * including the sample itself in the selection. The method first selects @@ -70,33 +123,15 @@ const Geometry::BoundingBox &MCInteractionVolume::getBoundingBox() const { * nextValue should return a flat random number between 0.0 & 1.0 * @return The generated point */ -Kernel::V3D MCInteractionVolume::generatePoint( - Kernel::PseudoRandomNumberGenerator &rng) const { +Kernel::V3D +MCInteractionVolume::generatePoint(Kernel::PseudoRandomNumberGenerator &rng) { for (size_t i = 0; i < m_maxScatterAttempts; i++) { - Kernel::V3D point; - int componentIndex; - if (m_env) { - componentIndex = rng.nextInt(0, static_cast<int>(m_env->nelements())) - 1; - } else { - componentIndex = -1; - } - - bool pointGenerated; - if (componentIndex == -1) { - pointGenerated = - m_sample->generatePointInObject(rng, m_activeRegion, 1, point); - } else { - pointGenerated = - m_env->getComponent(componentIndex) - .generatePointInObject(rng, m_activeRegion, 1, point); - } + int componentIndex = getComponentIndex(rng); + boost::optional<Kernel::V3D> pointGenerated = + generatePointInObjectByIndex(componentIndex, rng); if (pointGenerated) { - if (componentIndex == -1) { - m_sampleScatterPoints++; - } else { - m_envScatterPoints[componentIndex]++; - } - return point; + UpdateScatterPointCounts(componentIndex); + return *pointGenerated; } } throw std::runtime_error("MCInteractionVolume::generatePoint() - Unable to " @@ -119,7 +154,7 @@ Kernel::V3D MCInteractionVolume::generatePoint( */ double MCInteractionVolume::calculateAbsorption( Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &startPos, - const Kernel::V3D &endPos, double lambdaBefore, double lambdaAfter) const { + const Kernel::V3D &endPos, double lambdaBefore, double lambdaAfter) { // Generate scatter point. If there is an environment present then // first select whether the scattering occurs on the sample or the // environment. The attenuation for the path leading to the scatter point @@ -174,10 +209,10 @@ std::string MCInteractionVolume::generateScatterPointStats() const { scatterPointSummary << "Scatter point counts:" << std::endl; - int totalScatterPoints = m_sampleScatterPoints; - for (std::vector<int>::size_type i = 0; i < m_envScatterPoints.size(); i++) { - totalScatterPoints += m_envScatterPoints[i]; - } + int totalScatterPoints = + std::accumulate(m_envScatterPoints.begin(), m_envScatterPoints.end(), + m_sampleScatterPoints); + scatterPointSummary << "Total scatter points: " << totalScatterPoints << std::endl; diff --git a/Framework/Algorithms/test/MCAbsorptionStrategyTest.h b/Framework/Algorithms/test/MCAbsorptionStrategyTest.h index 31fcefa7323a45d1e1976f097f7598fd353fe191..c23ed83a607d67cf16349cc07d36b3dacb84db96 100644 --- a/Framework/Algorithms/test/MCAbsorptionStrategyTest.h +++ b/Framework/Algorithms/test/MCAbsorptionStrategyTest.h @@ -57,9 +57,8 @@ public: const double lambdaBefore(2.5), lambdaAfter(3.5); double factor(0.0), error(0.0); - std::string debugString; std::tie(factor, error) = - mcabsorb.calculate(rng, endPos, lambdaBefore, lambdaAfter, debugString); + mcabsorb.calculate(rng, endPos, lambdaBefore, lambdaAfter); TS_ASSERT_DELTA(0.0043828472, factor, 1e-08); TS_ASSERT_DELTA(1.0 / std::sqrt(nevents), error, 1e-08); } @@ -86,10 +85,8 @@ public: EXPECT_CALL(rng, nextValue()).WillRepeatedly(Return(0.5)); const double lambdaBefore(2.5), lambdaAfter(3.5); const V3D endPos(0.7, 0.7, 1.4); - std::string debugString; - TS_ASSERT_THROWS( - mcabs.calculate(rng, endPos, lambdaBefore, lambdaAfter, debugString), - const std::runtime_error &) + TS_ASSERT_THROWS(mcabs.calculate(rng, endPos, lambdaBefore, lambdaAfter), + const std::runtime_error &) } private: diff --git a/Framework/Algorithms/test/MCInteractionVolumeTest.h b/Framework/Algorithms/test/MCInteractionVolumeTest.h index ccf4ce62e9de9d9208ec41be0aa77020b33fa613..5e0c057231c563841b26b27431dfd5b4e17e2a79 100644 --- a/Framework/Algorithms/test/MCInteractionVolumeTest.h +++ b/Framework/Algorithms/test/MCInteractionVolumeTest.h @@ -16,6 +16,9 @@ #include <gmock/gmock.h> using Mantid::Algorithms::MCInteractionVolume; +using namespace ::testing; +using namespace Mantid::Kernel; +using namespace MonteCarloTesting; class MCInteractionVolumeTest : public CxxTest::TestSuite { public: @@ -30,7 +33,6 @@ public: // Success cases //---------------------------------------------------------------------------- void test_Bounding_Volume_Matches_Sample() { - using namespace MonteCarloTesting; auto sample = createTestSample(TestSampleType::SolidSphere); const auto sampleBox = sample.getShape().getBoundingBox(); MCInteractionVolume interactor(sample, sampleBox); @@ -42,8 +44,6 @@ public: void test_Absorption_In_Solid_Sample_Gives_Expected_Answer() { using Mantid::Kernel::V3D; - using namespace MonteCarloTesting; - using namespace ::testing; // Testing inputs const V3D startPos(-2.0, 0.0, 0.0), endPos(0.7, 0.7, 1.4); @@ -62,8 +62,6 @@ public: void test_Absorption_In_Sample_With_Hole_Container_Scatter_In_All_Segments() { using Mantid::Kernel::V3D; - using namespace MonteCarloTesting; - using namespace ::testing; // Testing inputs const V3D startPos(-2.0, 0.0, 0.0), endPos(2.0, 0.0, 0.0); @@ -95,8 +93,6 @@ public: void test_Absorption_In_Sample_And_Environment_Container_Scatter_In_All_Segments() { using Mantid::Kernel::V3D; - using namespace MonteCarloTesting; - using namespace ::testing; // Testing inputs const V3D startPos(-2.0, 0.0, 0.0), endPos(2.0, 0.0, 0.0); @@ -138,9 +134,7 @@ public: // Failure cases //---------------------------------------------------------------------------- void test_Construction_With_Invalid_Sample_Shape_Throws_Error() { - using Mantid::API::Sample; - - Sample sample; + Mantid::API::Sample sample; // nothing TS_ASSERT_THROWS( MCInteractionVolume mcv(sample, sample.getShape().getBoundingBox()), @@ -152,9 +146,6 @@ public: } void test_Throws_If_Point_Cannot_Be_Generated() { - using namespace Mantid::Kernel; - using namespace MonteCarloTesting; - using namespace ::testing; // Testing inputs const V3D startPos(-2.0, 0.0, 0.0), endPos(2.0, 0.0, 0.0); @@ -172,15 +163,11 @@ public: } void testGeneratePointConsidersAllComponents() { - using namespace ::testing; - using namespace Mantid::Kernel; - using namespace MonteCarloTesting; auto kit = createTestKit(); size_t maxAttempts(1); - using Mantid::API::Sample; - Sample sample; + Mantid::API::Sample sample; sample.setShape(ComponentCreationHelper::createSphere(1)); sample.setEnvironment( std::make_unique<Mantid::Geometry::SampleEnvironment>(*kit)); @@ -236,9 +223,6 @@ public: } void testGeneratePointRespectsActiveRegion() { - using namespace MonteCarloTesting; - using namespace ::testing; - using namespace Mantid::Kernel; auto kit = createTestKit(); size_t maxAttempts(1); diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/Container.h b/Framework/Geometry/inc/MantidGeometry/Instrument/Container.h index a18ef6de79a2968c954791d1aa2bb831268f3354..3698add9d3146f98bd55af45868d1cc3631b35e4 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/Container.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument/Container.h @@ -79,15 +79,16 @@ public: int getPointInObject(Kernel::V3D &point) const override { return m_shape->getPointInObject(point); } - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const size_t i, - Kernel::V3D &point) const override { - return m_shape->generatePointInObject(rng, i, point); - } - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, const size_t i, - Kernel::V3D &point) const override { - return m_shape->generatePointInObject(rng, activeRegion, i, point); + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const size_t i) const override { + return m_shape->generatePointInObject(rng, i); + } + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t i) const override { + return m_shape->generatePointInObject(rng, activeRegion, i); } detail::ShapeInfo::GeometryShape shape() const override { diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h b/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h index 4eadddaf38b5ba6bb08438fce5457d8585b7bfd0..bc92e93c1e53947ede4ccb41c88d04b42eb145ec 100644 --- a/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h +++ b/Framework/Geometry/inc/MantidGeometry/Objects/CSGObject.h @@ -165,11 +165,13 @@ public: int getPointInObject(Kernel::V3D &point) const override; /// Select a random point within the object - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const size_t, Kernel::V3D &point) const override; - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, const size_t, - Kernel::V3D &point) const override; + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const size_t) const override; + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t) const override; // Rendering member functions void draw() const override; diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h b/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h index c53e199de145f3bede302e622cf614934a4dd2a6..13586ebc709e2e54e02bf8dad154631af9c51798 100644 --- a/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h +++ b/Framework/Geometry/inc/MantidGeometry/Objects/IObject.h @@ -9,6 +9,7 @@ #include "MantidGeometry/DllConfig.h" #include "MantidGeometry/Rendering/ShapeInfo.h" +#include <boost/optional.hpp> #include <boost/shared_ptr.hpp> #include <map> #include <vector> @@ -70,13 +71,13 @@ public: virtual int getPointInObject(Kernel::V3D &point) const = 0; - virtual bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const size_t, - Kernel::V3D &point) const = 0; - virtual bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, - const size_t, - Kernel::V3D &point) const = 0; + virtual boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const size_t) const = 0; + virtual boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t) const = 0; virtual detail::ShapeInfo::GeometryShape shape() const = 0; virtual const detail::ShapeInfo &shapeInfo() const = 0; diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject.h b/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject.h index 55b2c489b47ed1a0f553eb9ce9da820828d540e6..c9cf8bea6b6c265329a29031ead321e6f98194eb 100644 --- a/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject.h +++ b/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject.h @@ -110,11 +110,13 @@ public: int getPointInObject(Kernel::V3D &point) const override; /// Select a random point within the object - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const size_t, Kernel::V3D &point) const override; - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, const size_t, - Kernel::V3D &point) const override; + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const size_t) const override; + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t) const override; // Rendering member functions void draw() const override; diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject2D.h b/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject2D.h index 229f591d1594be9a364073062279dac850ea63c6..1b4f83809f7ab5f4d332a789384e30fad2a3b6f4 100644 --- a/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject2D.h +++ b/Framework/Geometry/inc/MantidGeometry/Objects/MeshObject2D.h @@ -65,11 +65,13 @@ public: double &ymin, double &zmin) const override; int getPointInObject(Kernel::V3D &point) const override; - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const size_t, Kernel::V3D &point) const override; - bool generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, const size_t, - Kernel::V3D &point) const override; + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const size_t) const override; + boost::optional<Kernel::V3D> + generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t) const override; detail::ShapeInfo::GeometryShape shape() const override; const detail::ShapeInfo &shapeInfo() const override; void GetObjectGeom(detail::ShapeInfo::GeometryShape &type, diff --git a/Framework/Geometry/src/Objects/CSGObject.cpp b/Framework/Geometry/src/Objects/CSGObject.cpp index d6ec6752900cb8577f73212797757e1e1f926dc7..4afe79d3c8f990fa7d808d62e8121f2cfebc33f9 100644 --- a/Framework/Geometry/src/Objects/CSGObject.cpp +++ b/Framework/Geometry/src/Objects/CSGObject.cpp @@ -1982,12 +1982,12 @@ int CSGObject::getPointInObject(Kernel::V3D &point) const { * @param rng A reference to a PseudoRandomNumberGenerator where * nextValue should return a flat random number between 0.0 & 1.0 * @param maxAttempts The maximum number of attempts at generating a point - * @param point The generated point * @return whether a point was generated in the object or not */ -bool CSGObject::generatePointInObject(PseudoRandomNumberGenerator &rng, - const size_t maxAttempts, - V3D &point) const { +boost::optional<Kernel::V3D> +CSGObject::generatePointInObject(PseudoRandomNumberGenerator &rng, + const size_t maxAttempts) const { + boost::optional<V3D> point{boost::none}; // If the shape fills its bounding box well enough then the most efficient // way to get the point is just brute force. We'll try that first with // just a few attempts. @@ -2000,7 +2000,7 @@ bool CSGObject::generatePointInObject(PseudoRandomNumberGenerator &rng, boost::optional<V3D> maybePoint{ RandomPoint::inGenericShape(*this, rng, bruteForceAttempts)}; if (maybePoint) { - point = *maybePoint; + point = maybePoint; } else { switch (shape()) { case detail::ShapeInfo::GeometryShape::CUBOID: @@ -2018,15 +2018,10 @@ bool CSGObject::generatePointInObject(PseudoRandomNumberGenerator &rng, default: maybePoint = RandomPoint::inGenericShape( *this, rng, maxAttempts - bruteForceAttempts); - if (!maybePoint) { - return false; - } else { - point = *maybePoint; - break; - } + point = maybePoint; } } - return true; + return point; } /** @@ -2037,14 +2032,13 @@ bool CSGObject::generatePointInObject(PseudoRandomNumberGenerator &rng, * @param activeRegion Restrict point generation to this sub-region of the * object * @param maxAttempts The maximum number of attempts at generating a point - * @param point The generated point * @return whether a point was generated in the object or not */ -bool CSGObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, - const size_t maxAttempts, - V3D &point) const { - boost::optional<V3D> pointGenerated{boost::none}; +boost::optional<Kernel::V3D> +CSGObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t maxAttempts) const { + boost::optional<V3D> point{boost::none}; // We'll first try brute force. If the shape fills its bounding box // well enough, this should be the fastest method. // Increasing the brute force attemps speeds up the shapes that fill @@ -2053,9 +2047,8 @@ bool CSGObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, // shape, its dimension and orientation. const size_t bruteForceAttempts{ std::min(static_cast<size_t>(5), maxAttempts)}; - pointGenerated = - RandomPoint::bounded(*this, rng, activeRegion, bruteForceAttempts); - if (!pointGenerated) { + point = RandomPoint::bounded(*this, rng, activeRegion, bruteForceAttempts); + if (!point) { detail::ShapeInfo::GeometryShape shape; std::vector<Kernel::V3D> shapeVectors; double radius; @@ -2064,37 +2057,32 @@ bool CSGObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, GetObjectGeom(shape, shapeVectors, innerRadius, radius, height); switch (shape) { case detail::ShapeInfo::GeometryShape::CUBOID: - pointGenerated = RandomPoint::bounded<RandomPoint::inCuboid>( + point = RandomPoint::bounded<RandomPoint::inCuboid>( m_handler->shapeInfo(), rng, activeRegion, maxAttempts - bruteForceAttempts); break; case detail::ShapeInfo::GeometryShape::CYLINDER: - pointGenerated = RandomPoint::bounded<RandomPoint::inCylinder>( + point = RandomPoint::bounded<RandomPoint::inCylinder>( m_handler->shapeInfo(), rng, activeRegion, maxAttempts - bruteForceAttempts); break; case detail::ShapeInfo::GeometryShape::HOLLOWCYLINDER: - pointGenerated = RandomPoint::bounded<RandomPoint::inHollowCylinder>( + point = RandomPoint::bounded<RandomPoint::inHollowCylinder>( m_handler->shapeInfo(), rng, activeRegion, maxAttempts - bruteForceAttempts); break; case detail::ShapeInfo::GeometryShape::SPHERE: - pointGenerated = RandomPoint::bounded<RandomPoint::inSphere>( + point = RandomPoint::bounded<RandomPoint::inSphere>( m_handler->shapeInfo(), rng, activeRegion, maxAttempts - bruteForceAttempts); break; default: - pointGenerated = RandomPoint::bounded(*this, rng, activeRegion, - maxAttempts - bruteForceAttempts); + point = RandomPoint::bounded(*this, rng, activeRegion, + maxAttempts - bruteForceAttempts); break; } } - if (!pointGenerated) { - return false; - } else { - point = *pointGenerated; - return true; - } + return point; } /** diff --git a/Framework/Geometry/src/Objects/MeshObject.cpp b/Framework/Geometry/src/Objects/MeshObject.cpp index 150cefb38ca71cbb7a7aafd0109e661b8f4178ef..ae3e6252a8fa9a551a03096e3a17d980da98780f 100644 --- a/Framework/Geometry/src/Objects/MeshObject.cpp +++ b/Framework/Geometry/src/Objects/MeshObject.cpp @@ -383,18 +383,17 @@ int MeshObject::getPointInObject(Kernel::V3D &point) const { * @param rng A reference to a PseudoRandomNumberGenerator where * nextValue should return a flat random number between 0.0 & 1.0 * @param maxAttempts The maximum number of attempts at generating a point - * @param point The newly generated point - * @return Whether a point was generated or not + * @return The generated point */ -bool MeshObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const size_t maxAttempts, - Kernel::V3D &point) const { +boost::optional<Kernel::V3D> +MeshObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const size_t maxAttempts) const { const auto &bbox = getBoundingBox(); if (bbox.isNull()) { throw std::runtime_error("Object::generatePointInObject() - Invalid " "bounding box. Cannot generate new point."); } - return generatePointInObject(rng, bbox, maxAttempts, point); + return generatePointInObject(rng, bbox, maxAttempts); } /** @@ -405,23 +404,17 @@ bool MeshObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, * @param activeRegion Restrict point generation to this sub-region of the * object * @param maxAttempts The maximum number of attempts at generating a point - * @param point The newly generated point - * @return Whether a point was generated or not + * @return The generated point */ -bool MeshObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, - const BoundingBox &activeRegion, - const size_t maxAttempts, - Kernel::V3D &point) const { +boost::optional<Kernel::V3D> +MeshObject::generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, + const BoundingBox &activeRegion, + const size_t maxAttempts) const { - const auto pointGenerated = + const auto point = RandomPoint::bounded(*this, rng, activeRegion, maxAttempts); - if (!pointGenerated) { - return false; - } else { - point = *pointGenerated; - return true; - } + return point; } /** diff --git a/Framework/Geometry/src/Objects/MeshObject2D.cpp b/Framework/Geometry/src/Objects/MeshObject2D.cpp index f7ef600ba62fc5fd1357bbc77e77cd597c58c6dd..19fc9455fada0d9e4cdbc92ddeb78597f5c0251f 100644 --- a/Framework/Geometry/src/Objects/MeshObject2D.cpp +++ b/Framework/Geometry/src/Objects/MeshObject2D.cpp @@ -388,19 +388,18 @@ int MeshObject2D::getPointInObject(Kernel::V3D &point) const { return this->isValid(point) ? 1 : 0; } -bool MeshObject2D::generatePointInObject( - Kernel::PseudoRandomNumberGenerator & /*rng*/, const size_t /*unused*/, - Kernel::V3D & /*unused*/) const { +boost::optional<Kernel::V3D> MeshObject2D::generatePointInObject( + Kernel::PseudoRandomNumberGenerator & /*rng*/, + const size_t /*unused*/) const { // How this would work for a finite plane is not clear. Points within the // plane can of course be generated, but most implementations of this method // use the bounding box throw std::runtime_error("Not implemented."); } -bool MeshObject2D::generatePointInObject( +boost::optional<Kernel::V3D> MeshObject2D::generatePointInObject( Kernel::PseudoRandomNumberGenerator & /*rng*/, - const BoundingBox & /*activeRegion*/, const size_t /*unused*/, - Kernel::V3D & /*unused*/) const { + const BoundingBox & /*activeRegion*/, const size_t /*unused*/) const { // How this would work for a finite plane is not clear. Points within the // plane can of course be generated, but most implementations of this method diff --git a/Framework/Geometry/test/CSGObjectTest.h b/Framework/Geometry/test/CSGObjectTest.h index 0ffe03d5a58e6b6244e0934266c0dad13d6de397..c91431701249d966b35acffdb65aff1d75aeb371 100644 --- a/Framework/Geometry/test/CSGObjectTest.h +++ b/Framework/Geometry/test/CSGObjectTest.h @@ -730,14 +730,13 @@ public: // inside hole auto shell = ComponentCreationHelper::createHollowShell(0.5, 1.0); constexpr size_t maxAttempts{1}; - V3D point; - TS_ASSERT_EQUALS(shell->generatePointInObject(rng, maxAttempts, point), - true); + boost::optional<V3D> point = shell->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, false); constexpr double tolerance{1e-10}; - TS_ASSERT_DELTA(-1. + 2. * 0.55, point.X(), tolerance); - TS_ASSERT_DELTA(-1. + 2. * 0.65, point.Y(), tolerance); - TS_ASSERT_DELTA(-1. + 2. * 0.70, point.Z(), tolerance); + TS_ASSERT_DELTA(-1. + 2. * 0.55, point->X(), tolerance); + TS_ASSERT_DELTA(-1. + 2. * 0.65, point->Y(), tolerance); + TS_ASSERT_DELTA(-1. + 2. * 0.70, point->Z(), tolerance); } void testGeneratePointInsideCuboid() { @@ -759,14 +758,14 @@ public: auto cuboid = ComponentCreationHelper::createCuboid(xLength, yLength, zLength); constexpr size_t maxAttempts{0}; - V3D point; - TS_ASSERT_EQUALS(cuboid->generatePointInObject(rng, maxAttempts, point), - true); + boost::optional<V3D> point = + cuboid->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, false); constexpr double tolerance{1e-10}; - TS_ASSERT_DELTA(xLength - randX * 2. * xLength, point.X(), tolerance); - TS_ASSERT_DELTA(-yLength + randY * 2. * yLength, point.Y(), tolerance); - TS_ASSERT_DELTA(-zLength + randZ * 2. * zLength, point.Z(), tolerance); + TS_ASSERT_DELTA(xLength - randX * 2. * xLength, point->X(), tolerance); + TS_ASSERT_DELTA(-yLength + randY * 2. * yLength, point->Y(), tolerance); + TS_ASSERT_DELTA(-zLength + randZ * 2. * zLength, point->Z(), tolerance); } void testGeneratePointInsideCylinder() { @@ -793,18 +792,18 @@ public: auto cylinder = ComponentCreationHelper::createCappedCylinder( radius, height, bottomCentre, axis, "cyl"); constexpr size_t maxAttempts{0}; - V3D point; - TS_ASSERT_EQUALS(cylinder->generatePointInObject(rng, maxAttempts, point), - true); + boost::optional<V3D> point = + cylinder->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, false); // Global->cylinder local coordinates - point -= bottomCentre; + *point -= bottomCentre; constexpr double tolerance{1e-10}; const double polarAngle{2. * M_PI * randT}; const double radialLength{radius * std::sqrt(randR)}; const double axisLength{height * randZ}; - TS_ASSERT_DELTA(radialLength * std::cos(polarAngle), point.X(), tolerance); - TS_ASSERT_DELTA(radialLength * std::sin(polarAngle), point.Y(), tolerance); - TS_ASSERT_DELTA(axisLength, point.Z(), tolerance); + TS_ASSERT_DELTA(radialLength * std::cos(polarAngle), point->X(), tolerance); + TS_ASSERT_DELTA(radialLength * std::sin(polarAngle), point->Y(), tolerance); + TS_ASSERT_DELTA(axisLength, point->Z(), tolerance); } void testGeneratePointInsideHollowCylinder() { @@ -832,20 +831,20 @@ public: auto hollowCylinder = ComponentCreationHelper::createHollowCylinder( innerRadius, radius, height, bottomCentre, axis, "hol-cyl"); constexpr size_t maxAttempts{0}; - V3D point; - TS_ASSERT_EQUALS( - hollowCylinder->generatePointInObject(rng, maxAttempts, point), true); + boost::optional<V3D> point; + point = hollowCylinder->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, false); // Global->cylinder local coordinates - point -= bottomCentre; + *point -= bottomCentre; constexpr double tolerance{1e-10}; const double polarAngle{2. * M_PI * randT}; const double c1 = std::pow(innerRadius, 2); const double c2 = std::pow(radius, 2); const double radialLength{std::sqrt(c1 + (c2 - c1) * randR)}; const double axisLength{height * randZ}; - TS_ASSERT_DELTA(radialLength * std::cos(polarAngle), point.X(), tolerance); - TS_ASSERT_DELTA(radialLength * std::sin(polarAngle), point.Y(), tolerance); - TS_ASSERT_DELTA(axisLength, point.Z(), tolerance); + TS_ASSERT_DELTA(radialLength * std::cos(polarAngle), point->X(), tolerance); + TS_ASSERT_DELTA(radialLength * std::sin(polarAngle), point->Y(), tolerance); + TS_ASSERT_DELTA(axisLength, point->Z(), tolerance); } void testGeneratePointInsideSphere() { @@ -864,19 +863,19 @@ public: constexpr double radius{0.23}; auto sphere = ComponentCreationHelper::createSphere(radius); constexpr size_t maxAttempts{0}; - V3D point; - TS_ASSERT_EQUALS(sphere->generatePointInObject(rng, maxAttempts, point), - true); + boost::optional<V3D> point; + point = sphere->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, false); // Global->cylinder local coordinates constexpr double tolerance{1e-10}; const double azimuthalAngle{2. * M_PI * randT}; const double polarAngle{std::acos(2. * randF - 1.)}; const double r{radius * randR}; TS_ASSERT_DELTA(r * std::cos(azimuthalAngle) * std::sin(polarAngle), - point.X(), tolerance); + point->X(), tolerance); TS_ASSERT_DELTA(r * std::sin(azimuthalAngle) * std::sin(polarAngle), - point.Y(), tolerance); - TS_ASSERT_DELTA(r * std::cos(polarAngle), point.Z(), tolerance); + point->Y(), tolerance); + TS_ASSERT_DELTA(r * std::cos(polarAngle), point->Z(), tolerance); } void testGeneratePointInsideRespectsMaxAttempts() { @@ -893,9 +892,8 @@ public: // inside hole auto shell = ComponentCreationHelper::createHollowShell(0.5, 1.0); constexpr size_t maxAttempts{1}; - V3D point; - TS_ASSERT_EQUALS(shell->generatePointInObject(rng, maxAttempts, point), - false); + boost::optional<V3D> point = shell->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, true); } void testGeneratePointInsideRespectsActiveRegion() { @@ -916,15 +914,14 @@ public: // Create a thin infinite rectangular region to restrict point generation BoundingBox activeRegion(0.1, 0.1, 0.1, -0.1, -0.1, -0.1); constexpr size_t maxAttempts{1}; - V3D point; - TS_ASSERT_EQUALS( - ball->generatePointInObject(rng, activeRegion, maxAttempts, point), - true); + boost::optional<V3D> point = + ball->generatePointInObject(rng, activeRegion, maxAttempts); + TS_ASSERT_EQUALS(!point, false); // We should get the point generated from the second 'random' triplet. constexpr double tolerance{1e-10}; - TS_ASSERT_DELTA(-0.1 + randX * 0.2, point.X(), tolerance) - TS_ASSERT_DELTA(-0.1 + randY * 0.2, point.Y(), tolerance) - TS_ASSERT_DELTA(-0.1 + randZ * 0.2, point.Z(), tolerance) + TS_ASSERT_DELTA(-0.1 + randX * 0.2, point->X(), tolerance) + TS_ASSERT_DELTA(-0.1 + randY * 0.2, point->Y(), tolerance) + TS_ASSERT_DELTA(-0.1 + randZ * 0.2, point->Z(), tolerance) } void testSolidAngleSphere() @@ -1747,52 +1744,44 @@ public: void test_generatePointInside_Cuboid_With_ActiveRegion() { constexpr size_t maxAttempts{500}; - V3D point; for (size_t i{0}; i < m_npoints; ++i) { - m_cuboid->generatePointInObject(m_rng, m_activeRegion, maxAttempts, - point); + m_cuboid->generatePointInObject(m_rng, m_activeRegion, maxAttempts); } } void test_generatePointInside_Cylinder_With_ActiveRegion() { constexpr size_t maxAttempts{500}; - V3D point; for (size_t i{0}; i < m_npoints; ++i) { - m_cylinder->generatePointInObject(m_rng, m_activeRegion, maxAttempts, - point); + m_cylinder->generatePointInObject(m_rng, m_activeRegion, maxAttempts); } } void test_generatePointInside_Rotated_Cuboid() { constexpr size_t maxAttempts{500}; - V3D point; for (size_t i = 0; i < m_npoints; ++i) { - m_rotatedCuboid->generatePointInObject(m_rng, maxAttempts, point); + m_rotatedCuboid->generatePointInObject(m_rng, maxAttempts); } } void test_generatePointInside_Rotated_Cuboid_With_ActiveRegion() { constexpr size_t maxAttempts{500}; - V3D point; for (size_t i = 0; i < m_npoints; ++i) { - m_rotatedCuboid->generatePointInObject(m_rng, m_activeRegion, maxAttempts, - point); + m_rotatedCuboid->generatePointInObject(m_rng, m_activeRegion, + maxAttempts); } } void test_generatePointInside_Sphere() { constexpr size_t maxAttempts{500}; - V3D point; for (size_t i = 0; i < m_npoints; ++i) { - m_sphere->generatePointInObject(m_rng, maxAttempts, point); + m_sphere->generatePointInObject(m_rng, maxAttempts); } } void test_generatePointInside_sphericalShell() { constexpr size_t maxAttempts{500}; - V3D point; for (size_t i = 0; i < m_npoints; ++i) { - m_sphericalShell->generatePointInObject(m_rng, maxAttempts, point); + m_sphericalShell->generatePointInObject(m_rng, maxAttempts); } } diff --git a/Framework/Geometry/test/MeshObject2DTest.h b/Framework/Geometry/test/MeshObject2DTest.h index 9eabaf8328e70d9ffb3558966e9663847d0e758a..1aa472f160d7a3fad4c38eaf8f4420f42efd1855 100644 --- a/Framework/Geometry/test/MeshObject2DTest.h +++ b/Framework/Geometry/test/MeshObject2DTest.h @@ -332,8 +332,8 @@ public: // plane auto mesh = makeSimpleTriangleMesh(); testing::NiceMock<MockRNG> generator; - V3D point; - TS_ASSERT_THROWS(mesh.generatePointInObject(generator, 10, point), + boost::optional<V3D> point; + TS_ASSERT_THROWS(point = mesh.generatePointInObject(generator, 10), std::runtime_error &); } // Characterisation test. @@ -344,10 +344,10 @@ public: auto mesh = makeSimpleTriangleMesh(); testing::NiceMock<MockRNG> generator; Mantid::Geometry::BoundingBox boundingBox; - V3D point; - TS_ASSERT_THROWS( - mesh.generatePointInObject(generator, boundingBox, 10, point), - std::runtime_error &); + boost::optional<V3D> point; + TS_ASSERT_THROWS(point = + mesh.generatePointInObject(generator, boundingBox, 10), + std::runtime_error &); } // Characterisation test. diff --git a/Framework/Geometry/test/MeshObjectTest.h b/Framework/Geometry/test/MeshObjectTest.h index b18e51afc8199926e5ebad936dd72696ce84f2f6..ebd57726629da80bcce34a5b6bc575cd17abfa46 100644 --- a/Framework/Geometry/test/MeshObjectTest.h +++ b/Framework/Geometry/test/MeshObjectTest.h @@ -18,6 +18,8 @@ #include "MantidTestHelpers/ComponentCreationHelper.h" #include "MockRNG.h" +#include <boost/optional.hpp> + #include <cxxtest/TestSuite.h> #include <Poco/DOM/AutoPtr.h> @@ -846,14 +848,14 @@ public: // Random sequence set up so as to give point (0.90, 1.10, 0.65) auto geom_obj = createLShape(); size_t maxAttempts(1); - V3D point; + boost::optional<Kernel::V3D> point; TS_ASSERT_THROWS_NOTHING( - geom_obj->generatePointInObject(rng, maxAttempts, point)); + point = geom_obj->generatePointInObject(rng, maxAttempts)); const double tolerance(1e-10); - TS_ASSERT_DELTA(0.90, point.X(), tolerance); - TS_ASSERT_DELTA(1.10, point.Y(), tolerance); - TS_ASSERT_DELTA(0.65, point.Z(), tolerance); + TS_ASSERT_DELTA(0.90, point->X(), tolerance); + TS_ASSERT_DELTA(1.10, point->Y(), tolerance); + TS_ASSERT_DELTA(0.65, point->Z(), tolerance); } void testGeneratePointInsideRespectsMaxAttempts() { @@ -870,9 +872,9 @@ public: // which is outside the octahedron auto geom_obj = createOctahedron(); size_t maxAttempts(1); - V3D point; - TS_ASSERT_EQUALS(geom_obj->generatePointInObject(rng, maxAttempts, point), - false); + boost::optional<V3D> point; + point = geom_obj->generatePointInObject(rng, maxAttempts); + TS_ASSERT_EQUALS(!point, true); } void testVolumeOfCube() { @@ -1087,18 +1089,18 @@ public: void test_generatePointInside_Convex_Solid() { const size_t npoints(6000); const size_t maxAttempts(500); - V3D point; + boost::optional<V3D> point; for (size_t i = 0; i < npoints; ++i) { - octahedron->generatePointInObject(rng, maxAttempts, point); + point = octahedron->generatePointInObject(rng, maxAttempts); } } void test_generatePointInside_NonConvex_Solid() { const size_t npoints(6000); const size_t maxAttempts(500); - V3D point; + boost::optional<V3D> point; for (size_t i = 0; i < npoints; ++i) { - lShape->generatePointInObject(rng, maxAttempts, point); + point = lShape->generatePointInObject(rng, maxAttempts); } }