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 {
16using Geometry::Track;
17using Kernel::V3D;
18
19namespace Algorithms {
20
31MCInteractionVolume::MCInteractionVolume(const API::Sample &sample, const size_t maxScatterAttempts,
33 : m_sample(sample.getShape().clone()), m_env(nullptr), m_activeRegion(getFullBoundingBox()),
34 m_maxScatterAttempts(maxScatterAttempts), m_pointsIn(pointsIn) {
35 try {
36 m_env = &sample.getEnvironment();
37 assert(m_env);
38 if (m_env->nelements() == 0) {
39 throw std::invalid_argument("MCInteractionVolume() - Sample enviroment has zero components.");
40 }
41 } catch (std::runtime_error &) {
42 // swallow this as no defined environment from getEnvironment
43 }
44
45 bool atLeastOneValidShape = m_sample->hasValidShape();
46 if (!atLeastOneValidShape && m_env) {
47 for (size_t i = 0; i < m_env->nelements(); i++) {
49 atLeastOneValidShape = true;
50 break;
51 }
52 }
53 }
54 if (!atLeastOneValidShape) {
55 throw std::invalid_argument("MCInteractionVolume() - Either the Sample or one of the "
56 "environment parts must have a valid shape.");
57 }
58}
59
66 auto sampleBox = m_sample->getBoundingBox();
68 const auto &envBox = m_env->boundingBox();
69 sampleBox.grow(envBox);
70 }
71 return sampleBox;
72}
73
75
83 // the sample has componentIndex -1, env components are number 0 upwards
84 const int sampleIndex = -1;
85 const int firstEnvIndex = sampleIndex + 1;
86 int startIndex = sampleIndex;
87 int endIndex = m_env ? static_cast<int>(m_env->nelements()) - 1 : sampleIndex;
89 startIndex = firstEnvIndex;
91 endIndex = sampleIndex;
92 if (startIndex == endIndex) {
93 return startIndex;
94 } else {
95 return rng.nextInt(startIndex, endIndex);
96 }
97}
98
108boost::optional<Kernel::V3D>
110 boost::optional<Kernel::V3D> pointGenerated{boost::none};
111 if (componentIndex == -1) {
112 pointGenerated = m_sample->generatePointInObject(rng, m_activeRegion, 1);
113 } else {
114 pointGenerated = m_env->getComponent(componentIndex).generatePointInObject(rng, m_activeRegion, 1);
115 }
116 return pointGenerated;
117}
118
130 for (size_t i = 0; i < m_maxScatterAttempts; i++) {
131 int componentIndex = getComponentIndex(rng);
132 boost::optional<Kernel::V3D> pointGenerated = generatePointInObjectByIndex(componentIndex, rng);
133 if (pointGenerated) {
134 return {componentIndex, *pointGenerated};
135 }
136 }
137 throw std::runtime_error("MCInteractionVolume::generatePoint() - Unable to "
138 "generate point in object after " +
139 std::to_string(m_maxScatterAttempts) + " attempts");
140}
141
157 const Kernel::V3D &startPos, const Kernel::V3D &endPos,
158 MCInteractionStatistics &stats) const {
159 // Generate scatter point. If there is an environment present then
160 // first select whether the scattering occurs on the sample or the
161 // environment. The attenuation for the path leading to the scatter point
162 // is calculated in reverse, i.e. defining the track from the scatter pt
163 // backwards for simplicity with how the Track object works. This avoids
164 // having to understand exactly which object the scattering occurred in.
165 ComponentScatterPoint scatterPos;
166
167 scatterPos = generatePoint(rng);
168 stats.UpdateScatterPointCounts(scatterPos.componentIndex, false);
169
170 const auto toStart = normalize(startPos - scatterPos.scatterPoint);
171 auto beforeScatter = std::make_shared<Track>(scatterPos.scatterPoint, toStart);
172 int nlinks = m_sample->interceptSurface(*beforeScatter);
173 if (m_env) {
174 nlinks += m_env->interceptSurfaces(*beforeScatter);
175 }
176 // This should not happen but numerical precision means that it can
177 // occasionally occur with tracks that are very close to the surface
178 if (nlinks == 0) {
179 return {false, nullptr, nullptr};
180 }
181 stats.UpdateScatterPointCounts(scatterPos.componentIndex, true);
182
183 // Now track to final destination
184 const V3D scatteredDirec = normalize(endPos - scatterPos.scatterPoint);
185 auto afterScatter = std::make_shared<Track>(scatterPos.scatterPoint, scatteredDirec);
186 m_sample->interceptSurface(*afterScatter);
187 if (m_env) {
188 m_env->interceptSurfaces(*afterScatter);
189 }
190 stats.UpdateScatterAngleStats(toStart, scatteredDirec);
191 return {true, beforeScatter, afterScatter};
192}
193
194} // namespace Algorithms
195} // namespace Mantid
This class stores information about the sample used in particular run.
Definition: Sample.h:33
const Geometry::SampleEnvironment & getEnvironment() const
Get a reference to the sample's environment.
Definition: Sample.cpp:136
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.
MCInteractionVolume(const API::Sample &sample, const size_t maxScatterAttempts=5000, const ScatteringPointVicinity pointsIn=ScatteringPointVicinity::SAMPLEANDENVIRONMENT)
Construct the volume encompassing the sample + any environment kit.
const Geometry::BoundingBox getFullBoundingBox() const override
Returns the axis-aligned bounding box for the volume including env if m_pointsIn !...
const ScatteringPointVicinity m_pointsIn
const Geometry::SampleEnvironment * m_env
int getComponentIndex(Kernel::PseudoRandomNumberGenerator &rng) const
Randomly select a component across the sample/environment.
boost::optional< Kernel::V3D > generatePointInObjectByIndex(int componentIndex, Kernel::PseudoRandomNumberGenerator &rng) const
Generate a point in an object identified by an index.
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
const std::shared_ptr< Geometry::IObject > m_sample
ComponentScatterPoint generatePoint(Kernel::PseudoRandomNumberGenerator &rng) const
Generate point randomly across one of the components of the environment including the sample itself i...
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition: BoundingBox.h:34
void grow(const BoundingBox &other)
Grow the bounding box so that it also encompasses the given box.
virtual boost::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
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition: V3D.h:341
Helper class which provides the Collimation Length for SANS instruments.
std::string to_string(const wide_integer< Bits, Signed > &n)