Mantid
Loading...
Searching...
No Matches
DetectorSearcher.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 +
10#include "MantidKernel/Logger.h"
12
13#include <tuple>
14
17using namespace Mantid;
18using namespace Mantid::API;
19
20namespace {
21Kernel::Logger g_log("DetectorSearcher");
22}
23
24double getQSign() {
25 const auto convention = Kernel::ConfigService::Instance().getString("Q.convention");
26 return (convention == "Crystallography") ? -1.0 : 1.0;
27}
28
38 const Geometry::DetectorInfo &detInfo)
39 : m_usingFullRayTrace(instrument->containsRectDetectors() == Geometry::Instrument::ContainsState::Full),
40 m_crystallography_convention(getQSign()), m_detInfo(detInfo), m_instrument(instrument) {
41
42 /* Choose the search strategy to use
43 * If the instrument uses rectangular detectors (e.g. TOPAZ) then it is faster
44 * to run a full ray trace starting from the top of the instrument. This is
45 * due to the speed up of looking up a single pixel in the rectangular
46 * detector.
47 *
48 * If the instrument does not use rectangular detectors (e.g. WISH, CORELLI)
49 * then it is faster to use a nearest neighbour search to find the closest
50 * pixels, then check them for intersection.
51 * */
54 } else {
55 m_rayTracer = std::make_unique<InstrumentRayTracer>(instrument);
56 }
57}
58
62 std::vector<Eigen::Vector3d> points;
63 points.reserve(m_detInfo.size());
64 m_indexMap.reserve(m_detInfo.size());
65
66 const auto frame = m_instrument->getReferenceFrame();
67 auto beam = frame->vecPointingAlongBeam();
68 auto up = frame->vecPointingUp();
69
70 for (size_t pointNo = 0; pointNo < m_detInfo.size(); ++pointNo) {
71 if (m_detInfo.isMonitor(pointNo) || m_detInfo.isMasked(pointNo))
72 continue; // detector is a monitor or masked so don't use
73
74 // Calculate a unit Q vector for each detector
75 // This follows a method similar to that used in IntegrateEllipsoids
76 const auto pos = normalize(m_detInfo.position(pointNo));
77 auto E1 = (pos - beam) * -m_crystallography_convention;
78 const auto norm = E1.norm();
79 if (norm == 0.) {
81 } else {
82 E1 /= norm;
83 }
84
85 Eigen::Vector3d point(E1[0], E1[1], E1[2]);
86
87 // Ignore nonsensical points
88 if (point.hasNaN() || up.coLinear(beam, pos))
89 continue;
90
91 points.emplace_back(point);
92 m_indexMap.emplace_back(pointNo);
93 }
94
95 // create KDtree of cached detector Q vectors
96 m_detectorCacheSearch = std::make_unique<Kernel::NearestNeighbours<3>>(points);
97}
98
107 // quick check to see if this Q is valid
108 if (q.nullVector())
109 return std::make_tuple(false, 0);
110
111 // search using best strategy for current instrument
114 } else {
116 }
117}
118
128 const auto direction = convertQtoDirection(q);
129 m_rayTracer->traceFromSample(direction);
130 const auto det = m_rayTracer->getDetectorResult();
131
132 if (!det)
133 return std::make_tuple(false, 0);
134
135 const auto detIndex = m_detInfo.indexOf(det->getID());
136
137 if (m_detInfo.isMasked(detIndex) || m_detInfo.isMonitor(detIndex))
138 return std::make_tuple(false, 0);
139
140 return std::make_tuple(true, detIndex);
141}
142
152 const auto detectorDir = convertQtoDirection(q);
153 // find where this Q vector should intersect with "extended" space
154 // NOTE: increase the Nneighbors from 5 to 11 to cover a wide extended space
155 const auto neighbours = m_detectorCacheSearch->findNearest(Eigen::Vector3d(q[0], q[1], q[2]), 11);
156
157 // check if neighboring is empty
158 if (neighbours.empty()) {
159 g_log.information() << "empty neighbor list for given Q\n";
160 return std::make_tuple(false, 0);
161 }
162
163 const auto result = checkInteceptWithNeighbours(detectorDir, neighbours);
164 const auto hitDetector = std::get<0>(result);
165 const auto index = std::get<1>(result);
166
167 if (hitDetector) {
168 return std::make_tuple(true, m_indexMap[index]);
169 } else if (m_instrument->hasParameter("tube-gap")) {
170 // Tube Gap Parameter specifically applies to tube instruments
171 return handleTubeGap(detectorDir, neighbours);
172 }
173
174 return std::make_tuple(false, 0);
175}
176
189 std::vector<double> gaps = m_instrument->getNumberParameter("tube-gap", true);
190 if (!gaps.empty()) {
191 const auto gap = static_cast<double>(gaps.front());
192 // try adding and subtracting tube-gap in 3 q dimensions to see if you can
193 // find detectors on each side of tube gap
194 for (int i = 0; i < 3; i++) {
195 auto gapDir = V3D(0., 0., 0.);
196 gapDir[i] = gap;
197
198 auto beam1 = normalize(detectorDir + gapDir);
199 const auto result1 = checkInteceptWithNeighbours(beam1, neighbours);
200 const auto hit1 = std::get<0>(result1);
201
202 const auto beam2 = normalize(detectorDir - gapDir);
203 const auto result2 = checkInteceptWithNeighbours(beam2, neighbours);
204 const auto hit2 = std::get<0>(result2);
205
206 if (hit1 && hit2) {
207 // Set the detector to one of the neighboring pixels
208 return std::make_tuple(true, m_indexMap[std::get<1>(result1)]);
209 }
210 }
211 }
212
213 return std::make_tuple(false, 0);
214}
215
224 const V3D &direction, const Kernel::NearestNeighbours<3>::NearestNeighbourResults &neighbours) const {
225 Geometry::Track track(m_detInfo.samplePosition(), direction);
226 // Find which of the neighbours we actually intersect with
227 for (const auto &neighbour : neighbours) {
228 const auto index = std::get<1>(neighbour);
229 const auto &det = m_detInfo.detector(m_indexMap[index]);
230
232 if (!bb.doesLineIntersect(track))
233 continue;
234
235 const auto hitDetector = det.interceptSurface(track) > 0;
236 if (hitDetector)
237 return std::make_tuple(hitDetector, index);
238
239 track.reset(m_detInfo.samplePosition(), direction);
240 }
241
242 return std::make_tuple(false, 0);
243}
244
251 const auto norm_q = q.norm();
252 const auto refFrame = m_instrument->getReferenceFrame();
253 const V3D refBeamDir = refFrame->vecPointingAlongBeam();
254
255 const double qBeam = q.scalar_prod(refBeamDir) * m_crystallography_convention;
256 double one_over_wl = (norm_q * norm_q) / (2.0 * qBeam);
257
258 auto detectorDir = q * -m_crystallography_convention;
259 detectorDir[refFrame->pointingAlongBeam()] = one_over_wl - qBeam;
260 detectorDir.normalize();
261 return detectorDir;
262}
double getQSign()
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
DetectorSearchResult searchUsingNearestNeighbours(const Kernel::V3D &q)
Attempt to find a detector using a nearest neighbours search strategy.
Geometry::Instrument_const_sptr m_instrument
handle to the instrument to search for detectors in
DetectorSearchResult handleTubeGap(const Kernel::V3D &detectorDir, const Kernel::NearestNeighbours< 3 >::NearestNeighbourResults &neighbours)
Helper function to handle the tube gap parameter in tube instruments.
DetectorSearchResult findDetectorIndex(const Kernel::V3D &q)
Find a detector that intsects with the given Qlab vector.
std::tuple< bool, size_t > DetectorSearchResult
Search result type representing whether a detector was found and if so which detector index it was.
const double m_crystallography_convention
flag for whether the crystallography convention is to be used
std::unique_ptr< Geometry::InstrumentRayTracer > m_rayTracer
instrument ray tracer object for searching in rectangular detectors
DetectorSearchResult searchUsingInstrumentRayTracing(const Kernel::V3D &q)
Attempt to find a detector using a full instrument ray tracing strategy.
std::unique_ptr< Kernel::NearestNeighbours< 3 > > m_detectorCacheSearch
Detector search cache for fast look-up of detectors.
std::vector< size_t > m_indexMap
vector of detector indicies used in the search
Kernel::V3D convertQtoDirection(const Kernel::V3D &q) const
Helper function to convert a Qlab vector to a direction in detector space.
std::tuple< bool, size_t > checkInteceptWithNeighbours(const Kernel::V3D &direction, const Kernel::NearestNeighbours< 3 >::NearestNeighbourResults &neighbours) const
Check whether the given direction in detector space intercepts with a detector.
DetectorSearcher(const Geometry::Instrument_const_sptr &instrument, const Geometry::DetectorInfo &detInfo)
Create a new DetectorSearcher with the given instrument & detectors.
const bool m_usingFullRayTrace
flag for whether to use InstrumentRayTracer or NearestNeighbours
const Geometry::DetectorInfo & m_detInfo
detector info for the instrument
void createDetectorCache()
Helper function to build the nearest neighbour tree.
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition: BoundingBox.h:34
bool doesLineIntersect(const Track &track) const
Does a specified track intersect the bounding box.
Definition: BoundingBox.cpp:44
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
Definition: DetectorInfo.h:49
Kernel::V3D samplePosition() const
Returns the sample position.
bool isMasked(const size_t index) const
Returns true if the detector is masked.
Kernel::V3D position(const size_t index) const
Returns the position of the detector with given index.
const Geometry::IDetector & detector(const size_t index) const
Return a const reference to the detector with given index.
size_t indexOf(const detid_t id) const
Returns the index of the detector with the given detector ID.
size_t size() const
Returns the size of the DetectorInfo, i.e., the number of detectors in the instrument.
bool isMonitor(const size_t index) const
Returns true if the detector is a monitor.
This class is responsible for tracking rays and accumulating a list of objects that are intersected a...
Base Instrument Class.
Definition: Instrument.h:47
Defines a track as a start point and a direction.
Definition: Track.h:165
void reset(const Kernel::V3D &startPoint, const Kernel::V3D &direction)
Set a starting point and direction.
Definition: Track.cpp:45
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
std::vector< std::tuple< VectorType, size_t, double > > NearestNeighbourResults
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class for 3D vectors.
Definition: V3D.h:34
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
Definition: V3D.h:274
double norm() const noexcept
Definition: V3D.h:263
bool nullVector(const double tolerance=1e-3) const noexcept
Determine if the point is null.
Definition: V3D.cpp:241
std::complex< double > MANTID_API_DLL E1(std::complex< double > z)
Integral for Gamma.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition: V3D.h:341
Helper class which provides the Collimation Length for SANS instruments.