Mantid
Loading...
Searching...
No Matches
DetectorGroup.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 +
11#include "MantidKernel/Logger.h"
13#include "MantidKernel/V2D.h"
14
15#include <numeric>
16
17namespace Mantid::Geometry {
18namespace {
19// static logger
20Kernel::Logger g_log("DetectorGroup");
21} // namespace
22
23using Kernel::Quat;
24using Kernel::V2D;
25using Kernel::V3D;
26
30DetectorGroup::DetectorGroup() : IDetector(), m_id(), m_detectors(), group_topology(undef) {}
31
37DetectorGroup::DetectorGroup(const std::vector<IDetector_const_sptr> &dets)
38 : IDetector(), m_id(), m_detectors(), group_topology(undef) {
39 if (dets.empty()) {
40 g_log.error("Illegal attempt to create an empty DetectorGroup");
41 throw std::invalid_argument("Empty DetectorGroup objects are not allowed");
42 }
43 std::vector<IDetector_const_sptr>::const_iterator it;
44 for (it = dets.begin(); it != dets.end(); ++it) {
45 addDetector(*it);
46 }
47}
48
53 // the topology of the group become undefined and needs recalculation if new
54 // detector has been added to the group
56
57 // For now at least, the ID is the same as the first detector that is added
58 if (m_detectors.empty())
59 m_id = det->getID();
60
61 m_detectors.insert(DetCollection::value_type(det->getID(), det));
62}
63
65
66std::size_t DetectorGroup::nDets() const { return m_detectors.size(); }
67
77 V3D newPos = std::accumulate(m_detectors.cbegin(), m_detectors.cend(), V3D(),
78 [](const V3D &pos, const auto &detector) { return pos + detector.second->getPos(); });
79
80 // We can have very small values (< Tolerance) of each component that should
81 // be zero
82 if (std::abs(newPos[0]) < Mantid::Kernel::Tolerance)
83 newPos[0] = 0.0;
84 if (std::abs(newPos[1]) < Mantid::Kernel::Tolerance)
85 newPos[1] = 0.0;
86 if (std::abs(newPos[2]) < Mantid::Kernel::Tolerance)
87 newPos[2] = 0.0;
88
89 return newPos /= static_cast<double>(m_detectors.size()); // protection against divide by zero in V3D
90}
91
93std::optional<Kernel::V2D> DetectorGroup::getSideBySideViewPos() const { return std::nullopt; }
94
96double DetectorGroup::getDistance(const IComponent &comp) const {
97 double result =
98 std::accumulate(m_detectors.cbegin(), m_detectors.cend(), 0.0,
99 [&comp](double sum, const auto &detector) { return sum + detector.second->getDistance(comp); });
100 return result / static_cast<double>(m_detectors.size());
101}
102
105double DetectorGroup::getTwoTheta(const V3D &observer, const V3D &axis) const {
106 double result = 0.0;
107 DetCollection::const_iterator it;
108 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
109 const V3D sampleDetVec = (*it).second->getPos() - observer;
110 result += sampleDetVec.angle(axis);
111 }
112 return result / static_cast<double>(m_detectors.size());
113}
114
115/*
116Gives the average angle of a group of detectors from the observation point,
117relative to the axis given.
118Returned values are signed according to the rotation direction relative to the
119axis and the instrument up direction.
120@param observer : observer (usually sample)
121@param axis : scattering axis.
122@param instrumentUp : Instrument up direction
123@return signed theta
124*/
125double DetectorGroup::getSignedTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis,
126 const Kernel::V3D &instrumentUp) const {
127 double result = 0.0;
128 DetCollection::const_iterator it;
129 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
130 const V3D sampleDetVec = it->second->getPos() - observer;
131 double angle = sampleDetVec.angle(axis);
132
133 V3D cross = axis.cross_prod(sampleDetVec);
134 V3D normToSurface = axis.cross_prod(instrumentUp);
135 if (normToSurface.scalar_prod(cross) < 0) {
136 angle *= -1;
137 }
138 result += angle;
139 }
140 return result / static_cast<double>(m_detectors.size());
141}
142
144double DetectorGroup::getPhi() const {
145 V3D avgPos = this->getPos();
146 double phi(0.0), dummy1(0.0), dummy2(0.0);
147 avgPos.getSpherical(dummy1, dummy2, phi);
148 return phi * M_PI / 180.0;
149}
150
152double DetectorGroup::getPhiOffset(const double &offset) const {
153 double avgPos = getPhi();
154 return avgPos < 0 ? -(offset + avgPos) : offset - avgPos;
155}
156
161std::vector<detid_t> DetectorGroup::getDetectorIDs() const {
162 std::vector<detid_t> result;
163 result.reserve(m_detectors.size());
164 DetCollection::const_iterator it;
165 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
166 result.emplace_back((*it).first);
167 }
168 return result;
169}
170
175std::vector<IDetector_const_sptr> DetectorGroup::getDetectors() const {
176 std::vector<IDetector_const_sptr> result;
177 result.reserve(m_detectors.size());
178 DetCollection::const_iterator it;
179 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
180 result.emplace_back((*it).second);
181 }
182 return result;
183}
184
193 double result =
194 std::accumulate(m_detectors.cbegin(), m_detectors.cend(), 0.0,
195 [&params](double angle, const auto &det) { return angle + det.second->solidAngle(params); });
196 return result;
197}
198
203 return std::any_of(m_detectors.cbegin(), m_detectors.cend(),
204 [](const auto &detector) { return detector.second->isParametrized(); });
205}
206
213bool DetectorGroup::isValid(const V3D &point) const {
214 return std::any_of(m_detectors.cbegin(), m_detectors.cend(),
215 [&point](const auto &detector) { return detector.second->isValid(point); });
216}
217
223bool DetectorGroup::isOnSide(const V3D &point) const {
224 return std::any_of(m_detectors.cbegin(), m_detectors.cend(),
225 [&point](const auto &detector) { return detector.second->isOnSide(point); });
226}
227
236 DetCollection::const_iterator it;
237 it = m_detectors.begin();
238 if (it == m_detectors.end())
239 return 0;
240 return (*m_detectors.begin()).second->getPointInObject(point);
241}
242
249std::set<std::string> DetectorGroup::getParameterNames(bool recursive) const {
250 (void)recursive; // Avoid compiler warning
251 return std::set<std::string>();
252}
253
260std::map<std::string, ComponentID> DetectorGroup::getParameterNamesByComponent() const {
261 return std::map<std::string, ComponentID>();
262}
263
271std::string DetectorGroup::getParameterAsString(const std::string &pname, bool recursive) const {
272 (void)pname; // Avoid compiler warning
273 (void)recursive; // Avoid compiler warning
274 return "";
275}
276
284bool DetectorGroup::getParameterVisible(const std::string &pname, bool recursive) const {
285 (void)pname; // Avoid compiler warning
286 (void)recursive; // Avoid compiler warning
287 return false;
288}
289
296 // boundingBox = BoundingBox(); // this change may modify a lot of behaviour
297 // -> verify
298 for (const auto &detector : m_detectors) {
299 BoundingBox memberBox;
300 if (!boundingBox.isAxisAligned()) {
301 // coordinate system
302 const std::vector<V3D> *cs = &(boundingBox.getCoordSystem());
303 memberBox.realign(cs);
304 }
305 detector.second->getBoundingBox(memberBox);
306 boundingBox.grow(memberBox);
307 }
308}
317bool DetectorGroup::hasParameter(const std::string &name, bool recursive) const {
318 (void)recursive; // Avoid compiler warning
319 (void)name; // Avoid compiler warning
320 return false;
321}
323std::string DetectorGroup::getParameterType(const std::string & /*name*/, bool /*recursive = true*/) const {
324 return std::string("");
325}
326
328std::vector<double> DetectorGroup::getNumberParameter(const std::string & /*pname*/, bool /*recursive*/) const {
329 return std::vector<double>(0);
330}
331
333std::vector<V3D> DetectorGroup::getPositionParameter(const std::string & /*pname*/, bool /*recursive*/) const {
334 return std::vector<V3D>(0);
335}
336
338std::vector<Quat> DetectorGroup::getRotationParameter(const std::string & /*pname*/, bool /*recursive*/) const {
339 return std::vector<Quat>(0);
340}
341
343std::vector<std::string> DetectorGroup::getStringParameter(const std::string & /*pname*/, bool /*recursive*/) const {
344 return std::vector<std::string>(0);
345}
346
348std::vector<int> DetectorGroup::getIntParameter(const std::string & /*pname*/, bool /*recursive*/) const {
349 return std::vector<int>(0);
350}
351
353std::vector<bool> DetectorGroup::getBoolParameter(const std::string & /*pname*/, bool /*recursive*/) const {
354 return std::vector<bool>(0);
355}
356
359 if (group_topology == undef) {
361 }
362 center = this->groupCentre;
363 return group_topology;
364}
372 if (m_detectors.size() == 1) {
374
375 return;
376 }
377 this->groupCentre = this->getPos();
378 if (this->isValid(groupCentre)) {
380 } else {
381 // the topology can still be rectangular, but randomisation errors or small
382 // gaps between
383 // detectors caused central point not to belong to detectors; need more
384 // accrurate estinations
385 // assuming that distance between detectors can not be bigger then
386 // detector's half size
387 // get detector's size:
388 IDetector_const_sptr spFirstDet = this->m_detectors.begin()->second;
389
390 BoundingBox bbox;
391 spFirstDet->getBoundingBox(bbox);
392 V3D width = bbox.width();
393
394 // loop if any near point belongs to group;
395 for (int i = 0; i < 6; i++) {
396 int ic = int(i) / 2;
397 int is = (i % 2 == 0) ? -1 : 1;
398 V3D cs = groupCentre;
399 cs[ic] += is * width[ic] / 4;
400 if (this->isValid(cs)) { // if it is, finish and end
402 break;
403 }
404 }
405 // if not, consider this group to be a ring;
406 if (this->group_topology == undef) {
408 }
409 }
410}
411
412std::string DetectorGroup::getName() const {
413 std::string result;
414 DetCollection::const_iterator it;
415 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
416 result += (*it).second->getName() + this->getNameSeparator();
417 }
418 return result;
419}
420
421std::string DetectorGroup::getFullName() const {
422 std::string result;
423 DetCollection::const_iterator it;
424 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
425 result += (*it).second->getFullName() + this->getNameSeparator();
426 }
427 return result;
428}
429
431
434 throw std::runtime_error("A DetectorGroup cannot have a ParameterMap");
435}
436
438size_t DetectorGroup::index() const { throw std::runtime_error("A DetectorGroup cannot have an index"); }
439
440size_t DetectorGroup::registerContents(class ComponentVisitor & /*component*/) const {
441 throw std::runtime_error("DetectorGroup::registerContents. This should not "
442 "be called. DetectorGroups are not part of the "
443 "instrument. On-the-fly only.");
444}
445
446} // namespace Mantid::Geometry
std::string name
Definition Run.cpp:60
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
std::vector< Kernel::V3D > const & getCoordSystem() const
returns the coordinate system to which BB is alighned to;
Kernel::V3D width() const
Returns the width of the box.
Definition BoundingBox.h:97
bool isAxisAligned() const
Check if it is normal axis aligned bounding box or not.
void grow(const BoundingBox &other)
Grow the bounding box so that it also encompasses the given box.
void realign(std::vector< Kernel::V3D > const *const pCS=nullptr)
reallign the BB according to new coordinate system, provided earlier or specified as parameter;
ComponentVisitor : Visitor for IComponents.
std::string getParameterAsString(const std::string &pname, bool recursive=true) const override
Get a string representation of a parameter.
std::string getFullName() const override
Get the IComponent full path name.
std::vector< Kernel::Quat > getRotationParameter(const std::string &pname, bool recursive=true) const override
Get a parameter defined as a Kernel::Quaternion.
const Kernel::Material material() const override
Returns the material of the Object.
bool hasParameter(const std::string &name, bool recursive=true) const override
Returns a boolean indicating whether the parameter exists or not.
double getTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis) const override
Gives the average angle of a group of detectors from the observation point, relative to the axis give...
DetCollection m_detectors
The collection of grouped detectors.
virtual size_t registerContents(class ComponentVisitor &visitor) const override
detid_t getID() const override
Get the detector ID.
Kernel::V3D groupCentre
group centre is the geometrical centre of the detectors group calculated when the calculate group top...
std::string getName() const override
Get the IComponent name.
std::map< std::string, ComponentID > getParameterNamesByComponent() const override
return the parameter names and the component they are from
std::vector< double > getNumberParameter(const std::string &pname, bool recursive=true) const override
Get a parameter defined as a double.
bool isParametrized() const override
Return true if any detector in the group is parametrized.
void addDetector(const IDetector_const_sptr &det)
Add a detector to the collection.
void getBoundingBox(BoundingBox &boundingBox) const override
Get the bounding box for this component and store it in the given argument.
std::vector< std::string > getStringParameter(const std::string &pname, bool recursive=true) const override
Get a parameter defined as a string.
std::vector< bool > getBoolParameter(const std::string &pname, bool recursive=true) const override
Get a parameter defined as an integer.
std::string getNameSeparator() const
Return separator for list of names of detectors.
std::vector< detid_t > getDetectorIDs() const
What detectors are contained in the group?
std::string getParameterType(const std::string &name, bool recursive=true) const override
Detectors group assumed to be non-parameterized.
double solidAngle(const Geometry::SolidAngleParams &params) const override
Gives the total solid angle subtended by a group of detectors by summing the contributions from the i...
double getPhi() const override
Computes the average position and returns the phi value.
std::vector< Kernel::V3D > getPositionParameter(const std::string &pname, bool recursive=true) const override
Get a parameter defined as a Kernel::V3D.
std::set< std::string > getParameterNames(bool recursive=true) const override
Return the parameter names.
double getDistance(const IComponent &comp) const override
Gives the average distance of a group of detectors from the given component.
void calculateGroupTopology() const
function calculates the detectors arrangement (topology)
DetectorGroup()
Default constructor.
std::optional< Kernel::V2D > getSideBySideViewPos() const override
Side by side view override doesn't make sense for a detector group so return empty.
std::vector< IDetector_const_sptr > getDetectors() const
What detectors are contained in the group?
double getSignedTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis, const Kernel::V3D &instrumentUp) const override
Gives the signed angle of this detector object with respect to an axis.
bool isOnSide(const Kernel::V3D &point) const override
Does the point given lie on the surface of one of the detectors.
double getPhiOffset(const double &offset) const override
Computes the average position and returns the phi value.
const ParameterMap & parameterMap() const override
Helper for legacy access mode. Always throws for DetectorGroup.
std::vector< int > getIntParameter(const std::string &pname, bool recursive=true) const override
Get a parameter defined as an integer.
det_topology getTopology(Kernel::V3D &center) const override
returns the detector's group topology if it has been calculated before or invokes the procedure of ca...
Kernel::V3D getPos() const override
Returns the position of the DetectorGroup.
std::size_t nDets() const override
Get the number of physical detectors this object represents.
bool getParameterVisible(const std::string &pname, bool recursive=true) const override
Get a visibility attribute of a parameter.
int m_id
The ID of this effective detector.
size_t index() const override
Helper for legacy access mode. Always throws for DetectorGroup.
int getPointInObject(Kernel::V3D &point) const override
Try to find a point that lies within (or on) the object.
bool isValid(const Kernel::V3D &point) const override
isValid() is true if the point is inside any of the detectors, i.e.
det_topology group_topology
the parameter describes the topology of the detector's group namely if detectors form a box or a ring...
base class for Geometric IComponent
Definition IComponent.h:53
Interface class for detector objects.
Definition IDetector.h:43
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
A material is defined as being composed of a given element, defined as a PhysicalConstants::NeutronAt...
Definition Material.h:50
Class for 3D vectors.
Definition V3D.h:34
constexpr double scalar_prod(const V3D &v) const noexcept
Calculates the cross product.
Definition V3D.h:280
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Definition V3D.h:284
double angle(const V3D &) const
Angle between this and another vector.
Definition V3D.cpp:162
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Definition V3D.cpp:116
Mantid::Kernel::Logger g_log("Goniometer")
std::shared_ptr< const Mantid::Geometry::IDetector > IDetector_const_sptr
Shared pointer to IDetector (const version)
Definition IDetector.h:102
det_topology
Describes the topology of a detectors group used to calculate angular position and angular measures f...
Definition IDetector.h:31
constexpr double Tolerance
Standard tolerance value.
Definition Tolerance.h:12
int32_t detid_t
Typedef for a detector ID.