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
261std::string DetectorGroup::getParameterAsString(const std::string &pname, bool recursive) const {
262 (void)pname; // Avoid compiler warning
263 (void)recursive; // Avoid compiler warning
264 return "";
265}
266
274bool DetectorGroup::getParameterVisible(const std::string &pname, bool recursive) const {
275 (void)pname; // Avoid compiler warning
276 (void)recursive; // Avoid compiler warning
277 return false;
278}
279
286 // boundingBox = BoundingBox(); // this change may modify a lot of behaviour
287 // -> verify
288 for (const auto &detector : m_detectors) {
289 BoundingBox memberBox;
290 if (!boundingBox.isAxisAligned()) {
291 // coordinate system
292 const std::vector<V3D> *cs = &(boundingBox.getCoordSystem());
293 memberBox.realign(cs);
294 }
295 detector.second->getBoundingBox(memberBox);
296 boundingBox.grow(memberBox);
297 }
298}
307bool DetectorGroup::hasParameter(const std::string &name, bool recursive) const {
308 (void)recursive; // Avoid compiler warning
309 (void)name; // Avoid compiler warning
310 return false;
311}
313std::string DetectorGroup::getParameterType(const std::string & /*name*/, bool /*recursive = true*/) const {
314 return std::string("");
315}
316
318std::vector<double> DetectorGroup::getNumberParameter(const std::string & /*pname*/, bool /*recursive*/) const {
319 return std::vector<double>(0);
320}
321
323std::vector<V3D> DetectorGroup::getPositionParameter(const std::string & /*pname*/, bool /*recursive*/) const {
324 return std::vector<V3D>(0);
325}
326
328std::vector<Quat> DetectorGroup::getRotationParameter(const std::string & /*pname*/, bool /*recursive*/) const {
329 return std::vector<Quat>(0);
330}
331
333std::vector<std::string> DetectorGroup::getStringParameter(const std::string & /*pname*/, bool /*recursive*/) const {
334 return std::vector<std::string>(0);
335}
336
338std::vector<int> DetectorGroup::getIntParameter(const std::string & /*pname*/, bool /*recursive*/) const {
339 return std::vector<int>(0);
340}
341
343std::vector<bool> DetectorGroup::getBoolParameter(const std::string & /*pname*/, bool /*recursive*/) const {
344 return std::vector<bool>(0);
345}
346
349 if (group_topology == undef) {
351 }
352 center = this->groupCentre;
353 return group_topology;
354}
362 if (m_detectors.size() == 1) {
364
365 return;
366 }
367 this->groupCentre = this->getPos();
368 if (this->isValid(groupCentre)) {
370 } else {
371 // the topology can still be rectangular, but randomisation errors or small
372 // gaps between
373 // detectors caused central point not to belong to detectors; need more
374 // accrurate estinations
375 // assuming that distance between detectors can not be bigger then
376 // detector's half size
377 // get detector's size:
378 IDetector_const_sptr spFirstDet = this->m_detectors.begin()->second;
379
380 BoundingBox bbox;
381 spFirstDet->getBoundingBox(bbox);
382 V3D width = bbox.width();
383
384 // loop if any near point belongs to group;
385 for (int i = 0; i < 6; i++) {
386 int ic = int(i) / 2;
387 int is = (i % 2 == 0) ? -1 : 1;
388 V3D cs = groupCentre;
389 cs[ic] += is * width[ic] / 4;
390 if (this->isValid(cs)) { // if it is, finish and end
392 break;
393 }
394 }
395 // if not, consider this group to be a ring;
396 if (this->group_topology == undef) {
398 }
399 }
400}
401
402std::string DetectorGroup::getName() const {
403 std::string result;
404 DetCollection::const_iterator it;
405 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
406 result += (*it).second->getName() + this->getNameSeparator();
407 }
408 return result;
409}
410
411std::string DetectorGroup::getFullName() const {
412 std::string result;
413 DetCollection::const_iterator it;
414 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
415 result += (*it).second->getFullName() + this->getNameSeparator();
416 }
417 return result;
418}
419
421
424 throw std::runtime_error("A DetectorGroup cannot have a ParameterMap");
425}
426
428size_t DetectorGroup::index() const { throw std::runtime_error("A DetectorGroup cannot have an index"); }
429
430size_t DetectorGroup::registerContents(class ComponentVisitor & /*component*/) const {
431 throw std::runtime_error("DetectorGroup::registerContents. This should not "
432 "be called. DetectorGroups are not part of the "
433 "instrument. On-the-fly only.");
434}
435
436} // 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::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
Parameter map iterator typedef.
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.