Mantid
Loading...
Searching...
No Matches
MCInteractionVolume.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8#include "MantidAPI/Sample.h"
13#include <iomanip>
14
15namespace Mantid {
17using Geometry::Track;
18using Kernel::V3D;
19
20namespace Algorithms {
21
29 if (m_env) {
30 try {
31 if (m_env->nelements() == 0) {
32 throw std::invalid_argument("MCInteractionVolume() - Sample enviroment has zero components.");
33 }
34 } catch (std::runtime_error &) {
35 // swallow this as no defined environment from getEnvironment
36 }
37 }
38
39 bool atLeastOneValidShape = m_sample->hasValidShape();
40 if (!atLeastOneValidShape && m_env) {
41 for (size_t i = 0; i < m_env->nelements(); i++) {
43 atLeastOneValidShape = true;
44 break;
45 }
46 }
47 }
48 if (!atLeastOneValidShape) {
49 throw std::invalid_argument("MCInteractionVolume() - Either the Sample or one of the "
50 "environment parts must have a valid shape.");
51 }
52}
53
66std::shared_ptr<IMCInteractionVolume>
67MCInteractionVolume::create(const API::Sample &sample, const size_t maxScatterAttempts,
69 auto interactionVol =
70 std::shared_ptr<MCInteractionVolume>(new MCInteractionVolume(sample, maxScatterAttempts, pointsIn, gaugeVolume));
71 // init calls member functions that require instantiation of virtual functions so deferring this until after
72 // construction through a factory is preferable.
73 interactionVol->init();
74 return interactionVol;
75}
76
88MCInteractionVolume::MCInteractionVolume(const API::Sample &sample, const size_t maxScatterAttempts,
90 IObject_sptr gaugeVolume)
91 : m_sample(sample.getShape().clone()), m_env(sample.hasEnvironment() ? &sample.getEnvironment() : nullptr),
92 m_maxScatterAttempts(maxScatterAttempts), m_pointsIn(pointsIn), m_gaugeVolume(std::move(gaugeVolume)) {}
93
99
105
112 auto sampleBox = m_sample->getBoundingBox();
113 if (m_gaugeVolume != nullptr) {
114 sampleBox = m_gaugeVolume->getBoundingBox();
116 const auto &envBox = m_env->boundingBox();
117 sampleBox.grow(envBox);
118 }
119 return sampleBox;
120}
121
127
135 // the sample has componentIndex -1, env components are number 0 upwards
136 const int sampleIndex = -1;
137 const int firstEnvIndex = sampleIndex + 1;
138 int startIndex = sampleIndex;
139 int endIndex = m_env ? static_cast<int>(m_env->nelements()) - 1 : sampleIndex;
141 startIndex = firstEnvIndex;
143 endIndex = sampleIndex;
144 if (startIndex == endIndex) {
145 return startIndex;
146 } else {
147 return rng.nextInt(startIndex, endIndex);
148 }
149}
150
160std::optional<Kernel::V3D>
162 std::optional<Kernel::V3D> pointGenerated{std::nullopt};
163 std::optional<Kernel::V3D> tmpPoint{std::nullopt};
164 if (componentIndex == -1) {
165 if (m_gaugeVolume != nullptr) {
166 tmpPoint = m_gaugeVolume->generatePointInObject(rng, m_activeRegion, 1);
167 if (tmpPoint) {
168 if (m_sample->isValid(tmpPoint.value())) {
169 pointGenerated = tmpPoint;
170 }
171 }
172 } else {
173 pointGenerated = m_sample->generatePointInObject(rng, m_activeRegion, 1);
174 }
175 } else {
176 pointGenerated = m_env->getComponent(componentIndex).generatePointInObject(rng, m_activeRegion, 1);
177 }
178 return pointGenerated;
179}
180
192 for (size_t i = 0; i < m_maxScatterAttempts; i++) {
193 int componentIndex = getComponentIndex(rng);
194 std::optional<Kernel::V3D> pointGenerated = generatePointInObjectByIndex(componentIndex, rng);
195 if (pointGenerated) {
196 return {componentIndex, *pointGenerated};
197 }
198 }
199 throw std::runtime_error("MCInteractionVolume::generatePoint() - Unable to "
200 "generate point in object after " +
201 std::to_string(m_maxScatterAttempts) + " attempts");
202}
203
219 const Kernel::V3D &startPos, const Kernel::V3D &endPos,
220 MCInteractionStatistics &stats) const {
221 // Generate scatter point. If there is an environment present then
222 // first select whether the scattering occurs on the sample or the
223 // environment. The attenuation for the path leading to the scatter point
224 // is calculated in reverse, i.e. defining the track from the scatter pt
225 // backwards for simplicity with how the Track object works. This avoids
226 // having to understand exactly which object the scattering occurred in.
227 ComponentScatterPoint scatterPos;
228
229 scatterPos = generatePoint(rng);
230 stats.UpdateScatterPointCounts(scatterPos.componentIndex, false);
231
232 const auto toStart = normalize(startPos - scatterPos.scatterPoint);
233 auto beforeScatter = std::make_shared<Track>(scatterPos.scatterPoint, toStart);
234 int nlinks = m_sample->interceptSurface(*beforeScatter);
235 if (m_env) {
236 nlinks += m_env->interceptSurfaces(*beforeScatter);
237 }
238 // This should not happen but numerical precision means that it can
239 // occasionally occur with tracks that are very close to the surface
240 if (nlinks == 0) {
241 return {false, nullptr, nullptr};
242 }
243 stats.UpdateScatterPointCounts(scatterPos.componentIndex, true);
244
245 // Now track to final destination
246 const V3D scatteredDirec = normalize(endPos - scatterPos.scatterPoint);
247 auto afterScatter = std::make_shared<Track>(scatterPos.scatterPoint, scatteredDirec);
248 m_sample->interceptSurface(*afterScatter);
249 if (m_env) {
250 m_env->interceptSurfaces(*afterScatter);
251 }
252 stats.UpdateScatterAngleStats(toStart, scatteredDirec);
253 return {true, beforeScatter, afterScatter};
254}
255
256} // namespace Algorithms
257} // namespace Mantid
This class stores information about the sample used in particular run.
Definition Sample.h:33
Stores statistics relating to the tracks generated in MCInteractionVolume for a specific detector.
void UpdateScatterPointCounts(int componentIndex, bool pointUsed)
Update the scatter point counts.
void UpdateScatterAngleStats(const Kernel::V3D &toStart, const Kernel::V3D &scatteredDirec)
Update the scattering angle statistics.
Defines a volume where interactions of Tracks and Objects can take place.
Geometry::IObject_sptr getGaugeVolume() const override
Returns the defined gauge volume if one is present, otherwise returns nullptr.
const Geometry::BoundingBox getFullBoundingBox() const override
Returns the defined gauge volume if one is present, otherwise returns axis-aligned bounding box for t...
const ScatteringPointVicinity m_pointsIn
const Geometry::SampleEnvironment * m_env
int getComponentIndex(Kernel::PseudoRandomNumberGenerator &rng) const
Randomly select a component across the sample/environment.
std::optional< Kernel::V3D > generatePointInObjectByIndex(int componentIndex, Kernel::PseudoRandomNumberGenerator &rng) const
Generate a point in an object identified by an index.
static std::shared_ptr< IMCInteractionVolume > create(const API::Sample &sample, const size_t maxScatterAttempts=5000, const ScatteringPointVicinity pointsIn=ScatteringPointVicinity::SAMPLEANDENVIRONMENT, Geometry::IObject_sptr gaugeVolume=nullptr)
Factory Method for constructing the volume encompassing the sample + any environment kit.
void init() override
Construct the volume encompassing the sample + any environment kit.
void setGaugeVolume(Geometry::IObject_sptr gaugeVolume) override
Sets the gauge volume on the InteractionVolume.
virtual TrackPair calculateBeforeAfterTrack(Kernel::PseudoRandomNumberGenerator &rng, const Kernel::V3D &startPos, const Kernel::V3D &endPos, MCInteractionStatistics &stats) const override
Calculate a before scatter and after scatter track based on a scatter point in the volume given a sta...
void setActiveRegion(const Geometry::BoundingBox &region) override
Sets the active region volume on the InteractionVolume.
const std::shared_ptr< Geometry::IObject > m_sample
ComponentScatterPoint generatePoint(Kernel::PseudoRandomNumberGenerator &rng) const override
Generate point randomly across one of the components of the environment including the sample itself i...
MCInteractionVolume(const API::Sample &sample, const size_t maxScatterAttempts=5000, const ScatteringPointVicinity pointsIn=ScatteringPointVicinity::SAMPLEANDENVIRONMENT, Geometry::IObject_sptr gaugeVolume=nullptr)
Construct the volume encompassing the sample + any environment kit.
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
void grow(const BoundingBox &other)
Grow the bounding box so that it also encompasses the given box.
virtual std::optional< Kernel::V3D > generatePointInObject(Kernel::PseudoRandomNumberGenerator &rng, const size_t) const =0
virtual bool hasValidShape() const =0
const IObject & getComponent(const size_t index) const
Returns the requested IObject.
Geometry::BoundingBox boundingBox() const
int interceptSurfaces(Track &track) const
Update the given track with intersections within the environment.
Defines a 1D pseudo-random number generator, i.e.
virtual int nextInt(int start, int end)=0
Return the next integer in the sequence.
Class for 3D vectors.
Definition V3D.h:34
std::tuple< bool, std::shared_ptr< Geometry::Track >, std::shared_ptr< Geometry::Track > > TrackPair
std::shared_ptr< IObject > IObject_sptr
Typdef for a shared pointer.
Definition IObject.h:93
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition V3D.h:352
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)