Mantid
Loading...
Searching...
No Matches
DetectorInfo.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 +
7#include <utility>
8
9#include "MantidBeamline/DetectorInfo.h"
18#include "MantidKernel/Unit.h"
19
20namespace Mantid::Geometry {
26DetectorInfo::DetectorInfo(std::unique_ptr<Beamline::DetectorInfo> detectorInfo,
27 std::shared_ptr<const Geometry::Instrument> instrument,
28 std::shared_ptr<const std::vector<detid_t>> detectorIds,
29 std::shared_ptr<const std::unordered_map<detid_t, size_t>> detIdToIndexMap)
30 : m_detectorInfo(std::move(detectorInfo)), m_instrument(std::move(instrument)),
31 m_detectorIDs(std::move(detectorIds)), m_detIDToIndex(std::move(detIdToIndexMap)),
32 m_lastDetector(PARALLEL_GET_MAX_THREADS), m_lastIndex(PARALLEL_GET_MAX_THREADS, -1) {
33
34 // Note: This does not seem possible currently (the instrument objects is
35 // always allocated, even if it is empty), so this will not fail.
36 if (!m_instrument)
37 throw std::invalid_argument("DetectorInfo::DetectorInfo Workspace does not contain an instrument!");
38
39 if (m_detectorIDs->size() != m_detIDToIndex->size()) {
40 throw std::invalid_argument("DetectorInfo::DetectorInfo: ID and ID->index map do not match");
41 }
42}
43
49 : m_detectorInfo(std::make_unique<Beamline::DetectorInfo>(*other.m_detectorInfo)), m_instrument(other.m_instrument),
50 m_detectorIDs(other.m_detectorIDs), m_detIDToIndex(other.m_detIDToIndex),
51 m_lastDetector(PARALLEL_GET_MAX_THREADS), m_lastIndex(PARALLEL_GET_MAX_THREADS, -1) {}
52
55 if (detectorIDs() != rhs.detectorIDs())
56 throw std::runtime_error("DetectorInfo::operator=: Detector IDs in "
57 "assignment do not match. Assignment not "
58 "possible");
59 // Do NOT assign anything in the "wrapping" part of DetectorInfo. We simply
60 // assign the underlying Beamline::DetectorInfo.
61 *m_detectorInfo = *rhs.m_detectorInfo;
62 return *this;
63}
64
65// Defined as default in source for forward declaration with std::unique_ptr.
67
77bool DetectorInfo::isEquivalent(const DetectorInfo &other) const {
78 return m_detectorInfo->isEquivalent(*other.m_detectorInfo);
79}
80
83size_t DetectorInfo::size() const { return m_detectorIDs->size(); }
84
86bool DetectorInfo::isScanning() const { return m_detectorInfo->isScanning(); }
87
89bool DetectorInfo::isMonitor(const size_t index) const { return m_detectorInfo->isMonitor(index); }
90
92bool DetectorInfo::isMonitor(const std::pair<size_t, size_t> &index) const { return m_detectorInfo->isMonitor(index); }
93
95bool DetectorInfo::isMasked(const size_t index) const { return m_detectorInfo->isMasked(index); }
96
98bool DetectorInfo::isMasked(const std::pair<size_t, size_t> &index) const { return m_detectorInfo->isMasked(index); }
99
101bool DetectorInfo::hasMaskedDetectors() const { return m_detectorInfo->hasMaskedDetectors(); }
102
108double DetectorInfo::l2(const size_t index) const {
109 if (!isMonitor(index))
110 return position(index).distance(samplePosition());
111 else
112 return position(index).distance(sourcePosition()) - l1();
113}
114
120double DetectorInfo::l2(const std::pair<size_t, size_t> &index) const {
121 if (!isMonitor(index))
122 return position(index).distance(samplePosition());
123 else
124 return position(index).distance(sourcePosition()) - l1();
125}
126
128double DetectorInfo::twoTheta(const size_t index) const {
129 if (isMonitor(index))
130 throw std::logic_error("Two theta (scattering angle) is not defined for monitors.");
131
132 const auto samplePos = samplePosition();
133 const auto beamLine = samplePos - sourcePosition();
134
135 if (beamLine.nullVector()) {
136 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
137 }
138
139 const auto sampleDetVec = position(index) - samplePos;
140 return sampleDetVec.angle(beamLine);
141}
142
144double DetectorInfo::twoTheta(const std::pair<size_t, size_t> &index) const {
145 if (isMonitor(index))
146 throw std::logic_error("Two theta (scattering angle) is not defined for monitors.");
147
148 const auto samplePos = samplePosition();
149 const auto beamLine = samplePos - sourcePosition();
150
151 if (beamLine.nullVector()) {
152 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
153 }
154
155 const auto sampleDetVec = position(index) - samplePos;
156 return sampleDetVec.angle(beamLine);
157}
158
160double DetectorInfo::signedTwoTheta(const size_t index) const {
161 if (isMonitor(index))
162 throw std::logic_error("Two theta (scattering angle) is not defined for monitors.");
163
164 const auto samplePos = samplePosition();
165 const auto beamLine = samplePos - sourcePosition();
166
167 if (beamLine.nullVector()) {
168 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
169 }
170 // Get the axis defining the sign
171 const auto &instrumentUpAxis = m_instrument->getReferenceFrame()->vecThetaSign();
172
173 const auto sampleDetVec = position(index) - samplePos;
174 double angle = sampleDetVec.angle(beamLine);
175
176 const auto cross = beamLine.cross_prod(sampleDetVec);
177 const auto normToSurface = beamLine.cross_prod(instrumentUpAxis);
178 if (normToSurface.scalar_prod(cross) < 0) {
179 angle *= -1;
180 }
181 return angle;
182}
183
185double DetectorInfo::signedTwoTheta(const std::pair<size_t, size_t> &index) const {
186 if (isMonitor(index))
187 throw std::logic_error("Two theta (scattering angle) is not defined for monitors.");
188
189 const auto samplePos = samplePosition();
190 const auto beamLine = samplePos - sourcePosition();
191
192 if (beamLine.nullVector()) {
193 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
194 }
195 // Get the axis defining the sign
196 const auto &instrumentUpAxis = m_instrument->getReferenceFrame()->vecThetaSign();
197
198 const auto sampleDetVec = position(index) - samplePos;
199 double angle = sampleDetVec.angle(beamLine);
200
201 const auto cross = beamLine.cross_prod(sampleDetVec);
202 const auto normToSurface = beamLine.cross_prod(instrumentUpAxis);
203 if (normToSurface.scalar_prod(cross) < 0) {
204 angle *= -1;
205 }
206 return angle;
207}
208
209double DetectorInfo::azimuthal(const size_t index) const {
210 if (isMonitor(index))
211 throw std::logic_error("Azimuthal angle is not defined for monitors");
212
213 const auto samplePos = samplePosition();
214 const auto beamLine = samplePos - sourcePosition();
215
216 if (beamLine.nullVector()) {
217 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
218 }
219
220 const auto sampleDetVec = position(index) - samplePos;
221 const auto beamLineNormalized = Kernel::normalize(beamLine);
222
223 // generate the vertical axis
224 const auto origHorizontal = m_instrument->getReferenceFrame()->vecPointingHorizontal();
225 const auto vertical = beamLineNormalized.cross_prod(origHorizontal);
226 if (vertical.scalar_prod(m_instrument->getReferenceFrame()->vecPointingUp()) <= 0.)
227 throw std::runtime_error("Failed to create up axis orthogonal to the beam direction");
228
229 // generate the horizontal axis perpendicular to the other two
230 const auto horizontal = vertical.cross_prod(beamLineNormalized);
231 if (origHorizontal.scalar_prod(horizontal) <= 0.)
232 throw std::runtime_error("Failed to create horizontal axis orthogonal to the beam direction");
233
234 const double dotHorizontal = sampleDetVec.scalar_prod(horizontal);
235 const double dotVertical = sampleDetVec.scalar_prod(vertical);
236
237 return atan2(dotVertical, dotHorizontal);
238}
239
240double DetectorInfo::azimuthal(const std::pair<size_t, size_t> &index) const {
241 if (isMonitor(index))
242 throw std::logic_error("Azimuthal angle is not defined for monitors");
243
244 const auto samplePos = samplePosition();
245 const auto beamLine = samplePos - sourcePosition();
246
247 if (beamLine.nullVector()) {
248 throw Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
249 }
250
251 const auto sampleDetVec = position(index) - samplePos;
252 const auto beamLineNormalized = Kernel::normalize(beamLine);
253
254 // generate the vertical axis
255 const auto origHorizontal = m_instrument->getReferenceFrame()->vecPointingHorizontal();
256 const auto vertical = beamLineNormalized.cross_prod(origHorizontal);
257 if (vertical.scalar_prod(m_instrument->getReferenceFrame()->vecPointingUp()) <= 0.)
258 throw std::runtime_error("Failed to create up axis orthogonal to the beam direction");
259
260 // generate the horizontal axis perpendicular to the other two
261 const auto horizontal = vertical.cross_prod(beamLineNormalized);
262 if (origHorizontal.scalar_prod(horizontal) <= 0.)
263 throw std::runtime_error("Failed to create horizontal axis orthogonal to the beam direction");
264
265 const double dotHorizontal = sampleDetVec.scalar_prod(horizontal);
266 const double dotVertical = sampleDetVec.scalar_prod(vertical);
267
268 return atan2(dotVertical, dotHorizontal);
269}
270
271std::tuple<double, double, double> DetectorInfo::diffractometerConstants(const size_t index,
272 std::vector<detid_t> &calibratedDets,
273 std::vector<detid_t> &uncalibratedDets) const {
274 auto det = m_instrument->getDetector((*m_detectorIDs)[index]);
275 auto pmap = m_instrument->getParameterMap();
276 auto par = pmap->get(det.get(), "DIFC");
277 if (par) {
278 double difc = par->value<double>();
279 calibratedDets.push_back((*m_detectorIDs)[index]);
280 double difa = 0., tzero = 0.;
281 par = pmap->get(det.get(), "DIFA");
282 if (par)
283 difa = par->value<double>();
284 par = pmap->get(det.get(), "TZERO");
285 if (par)
286 tzero = par->value<double>();
287 return {difa, difc, tzero};
288 } else {
289 // if calibrated difc not available, revert to uncalibrated difc with other
290 // two constants=0
291 uncalibratedDets.push_back((*m_detectorIDs)[index]);
292 double difc = difcUncalibrated(index);
293 return {0., difc, 0.};
294 }
295}
296
297double DetectorInfo::difcUncalibrated(const size_t index) const {
299}
300
301std::pair<double, double> DetectorInfo::geographicalAngles(const size_t index) const {
302 const auto samplePos = samplePosition();
303 const auto sampleDetVec = position(index) - samplePos;
304 const double upCoord = sampleDetVec[m_instrument->getReferenceFrame()->pointingUp()];
305 const double beamCoord = sampleDetVec[m_instrument->getReferenceFrame()->pointingAlongBeam()];
306 const double leftoverCoord = sampleDetVec[m_instrument->getReferenceFrame()->pointingHorizontal()];
307 const double lat = std::atan2(upCoord, std::hypot(leftoverCoord, beamCoord));
308 const double lon = std::atan2(leftoverCoord, beamCoord);
309 return std::pair<double, double>(lat, lon);
310}
311
312std::pair<double, double> DetectorInfo::geographicalAngles(const std::pair<size_t, size_t> &index) const {
313 const auto samplePos = samplePosition();
314 const auto sampleDetVec = position(index) - samplePos;
315 const double upCoord = sampleDetVec[m_instrument->getReferenceFrame()->pointingUp()];
316 const double beamCoord = sampleDetVec[m_instrument->getReferenceFrame()->pointingAlongBeam()];
317 const double leftoverCoord = sampleDetVec[m_instrument->getReferenceFrame()->pointingHorizontal()];
318 const double lat = std::atan2(upCoord, std::hypot(leftoverCoord, beamCoord));
319 const double lon = std::atan2(leftoverCoord, beamCoord);
320 return std::pair<double, double>(lat, lon);
321}
322
325
327Kernel::V3D DetectorInfo::position(const std::pair<size_t, size_t> &index) const {
328 return Kernel::toV3D(m_detectorInfo->position(index));
329}
330
333 return Kernel::toQuat(m_detectorInfo->rotation(index));
334}
335
337Kernel::Quat DetectorInfo::rotation(const std::pair<size_t, size_t> &index) const {
338 return Kernel::toQuat(m_detectorInfo->rotation(index));
339}
340
342void DetectorInfo::setMasked(const size_t index, bool masked) { m_detectorInfo->setMasked(index, masked); }
343
345void DetectorInfo::setMasked(const std::pair<size_t, size_t> &index, bool masked) {
346 m_detectorInfo->setMasked(index, masked);
347}
348
354 for (size_t i = 0; i < size(); ++i)
355 m_detectorInfo->setMasked(i, false);
356}
357
360
363}
364
366void DetectorInfo::setPosition(const std::pair<size_t, size_t> &index, const Kernel::V3D &position) {
369}
370
371// Clear any parameters whose value is only valid for specific positions
372// Currently diffractometer constants
374 auto det = m_instrument->getDetector((*m_detectorIDs)[index]);
375 auto pmap = m_instrument->getParameterMap();
376 pmap->clearParametersByName("DIFA", det.get());
377 pmap->clearParametersByName("DIFC", det.get());
378 pmap->clearParametersByName("TZERO", det.get());
379}
380
384}
385
387void DetectorInfo::setRotation(const std::pair<size_t, size_t> &index, const Kernel::Quat &rotation) {
389}
390
392const Geometry::IDetector &DetectorInfo::detector(const size_t index) const { return getDetector(index); }
393
396
399
401double DetectorInfo::l1() const { return m_detectorInfo->l1(); }
402
404const std::vector<detid_t> &DetectorInfo::detectorIDs() const { return *m_detectorIDs; }
405
406std::size_t DetectorInfo::indexOf(const detid_t id) const {
407 try {
408 return m_detIDToIndex->at(id);
409 } catch (const std::out_of_range &) {
410 // customize the error message
411 std::stringstream msg;
412 msg << "Failed to find detector with id=" << id;
413 throw std::out_of_range(msg.str());
414 }
415}
416
418size_t DetectorInfo::scanCount() const { return m_detectorInfo->scanCount(); }
419
424const std::vector<std::pair<Types::Core::DateAndTime, Types::Core::DateAndTime>> DetectorInfo::scanIntervals() const {
425 const auto &intervals = m_detectorInfo->scanIntervals();
426 return {intervals.begin(), intervals.end()};
427}
428
430
432
434 auto thread = static_cast<size_t>(PARALLEL_THREAD_NUMBER);
435 if (m_lastIndex[thread] != index) {
436 m_lastIndex[thread] = index;
437 m_lastDetector[thread] = m_instrument->getDetector((*m_detectorIDs)[index]);
438 }
439
440 return *m_lastDetector[thread];
441}
442
444std::shared_ptr<const Geometry::IDetector> DetectorInfo::getDetectorPtr(const size_t index) const {
445 auto thread = static_cast<size_t>(PARALLEL_THREAD_NUMBER);
446 static_cast<void>(getDetector(index));
447 return m_lastDetector[thread];
448}
449
450// Begin method for iterator
452
453// End method for iterator
455
456} // namespace Mantid::Geometry
const std::vector< double > & rhs
double position
Definition: GetAllEi.cpp:154
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define PARALLEL_THREAD_NUMBER
#define PARALLEL_GET_MAX_THREADS
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
DetectorInfoIterator for random access iteration over DetectorInfo.
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
Definition: DetectorInfo.h:49
void clearPositionDependentParameters(const size_t index)
double twoTheta(const size_t index) const
Returns 2 theta (scattering angle w.r.t. to beam direction).
size_t scanCount() const
Returns the scan count of the detector with given detector index.
void setPosition(const size_t index, const Kernel::V3D &position)
Set the absolute position of the detector with given index. Not thread safe.
std::shared_ptr< const Geometry::Instrument > m_instrument
Definition: DetectorInfo.h:129
double l2(const size_t index) const
Returns L2 (distance from sample to spectrum).
std::shared_ptr< const std::unordered_map< detid_t, size_t > > m_detIDToIndex
Definition: DetectorInfo.h:131
const Geometry::IDetector & getDetector(const size_t index) const
Kernel::V3D samplePosition() const
Returns the sample position.
std::pair< double, double > geographicalAngles(const size_t index) const
DetectorInfoIterator< DetectorInfo > end()
bool hasMaskedDetectors() const
Returns true if there are masked detectors.
Kernel::Quat rotation(const size_t index) const
Returns the rotation of the detector with given index.
bool isMasked(const size_t index) const
Returns true if the detector is masked.
void setMasked(const size_t index, bool masked)
Set the mask flag of the detector with given index. Not thread safe.
const std::vector< detid_t > & detectorIDs() const
Returns a sorted vector of all detector IDs.
Kernel::V3D position(const size_t index) const
Returns the position of the detector with given index.
void clearMaskFlags()
Sets all mask flags to false (unmasked).
bool isEquivalent(const DetectorInfo &other) const
Returns true if the content of this is equivalent to the content of other.
const DetectorInfoIterator< const DetectorInfo > cend() const
std::vector< std::shared_ptr< const Geometry::IDetector > > m_lastDetector
Definition: DetectorInfo.h:133
double signedTwoTheta(const size_t index) const
Returns signed 2 theta (signed scattering angle w.r.t. to beam direction).
double l1() const
Returns L1 (distance from source to sample).
void setRotation(const size_t index, const Kernel::Quat &rotation)
Set the absolute rotation of the detector with given index. Not thread safe.
std::vector< size_t > m_lastIndex
Definition: DetectorInfo.h:134
Kernel::V3D sourcePosition() const
Returns the source position.
std::tuple< double, double, double > diffractometerConstants(const size_t index, std::vector< detid_t > &calibratedDets, std::vector< detid_t > &uncalibratedDets) const
const Geometry::IDetector & detector(const size_t index) const
Return a const reference to the detector with given index.
DetectorInfo(std::unique_ptr< Beamline::DetectorInfo > detectorInfo, std::shared_ptr< const Geometry::Instrument > instrument, std::shared_ptr< const std::vector< detid_t > > detectorIds, std::shared_ptr< const std::unordered_map< detid_t, size_t > > detIdToIndexMap)
Construct DetectorInfo based on an Instrument.
const DetectorInfoIterator< const DetectorInfo > cbegin() const
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.
DetectorInfoIterator< DetectorInfo > begin()
std::unique_ptr< Beamline::DetectorInfo > m_detectorInfo
Pointer to the actual DetectorInfo object (non-wrapping part).
Definition: DetectorInfo.h:127
bool isMonitor(const size_t index) const
Returns true if the detector is a monitor.
bool isScanning() const
Returns true if the beamline has scanning detectors.
std::shared_ptr< const std::vector< detid_t > > m_detectorIDs
Definition: DetectorInfo.h:130
double azimuthal(const size_t index) const
DetectorInfo & operator=(const DetectorInfo &rhs)
Assigns the contents of the non-wrapping part of rhs to this.
double difcUncalibrated(const size_t index) const
const std::vector< std::pair< Types::Core::DateAndTime, Types::Core::DateAndTime > > scanIntervals() const
Returns the scan interval of the detector with given index.
std::shared_ptr< const Geometry::IDetector > getDetectorPtr(const size_t index) const
Helper used by SpectrumInfo.
Interface class for detector objects.
Definition: IDetector.h:43
Exception for errors associated with the instrument definition.
Definition: Exception.h:220
Class for quaternions.
Definition: Quat.h:39
Class for 3D vectors.
Definition: V3D.h:34
DetectorInfoIterator< DetectorInfo > DetectorInfoIt
Definition: DetectorInfo.h:137
DetectorInfoIterator< const DetectorInfo > DetectorInfoConstIt
Definition: DetectorInfo.h:138
MANTID_KERNEL_DLL double tofToDSpacingFactor(const double l1, const double l2, const double twoTheta, const double offset)
Calculate and return conversion factor from tof to d-spacing.
Definition: Unit.cpp:568
Kernel::Quat toQuat(const Eigen::Quaterniond &quat)
Converts Eigen::Quaterniond to Kernel::Quat.
Eigen::Vector3d toVector3d(const Kernel::V3D &vec)
Converts Kernel::V3D to Eigen::Vector3d.
Kernel::V3D toV3D(const Eigen::Vector3d &vec)
This header provides conversion helpers between vector and rotation types in MantidKernel and equival...
MANTID_KERNEL_DLL V3D normalize(V3D v)
Normalizes a V3D.
Definition: V3D.h:341
Eigen::Quaterniond toQuaterniond(const Kernel::Quat &quat)
Converts Kernel::Quat to Eigen::Quaterniond.
int32_t detid_t
Typedef for a detector ID.
Definition: SpectrumInfo.h:21
Generate a tableworkspace to store the calibration results.
STL namespace.