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
14#include <numeric>
15
16namespace Mantid::Geometry {
17namespace {
18// static logger
19Kernel::Logger g_log("DetectorGroup");
20} // namespace
21
22using Kernel::Quat;
23using Kernel::V3D;
24
28DetectorGroup::DetectorGroup() : IDetector(), m_id(), m_detectors(), group_topology(undef) {}
29
35DetectorGroup::DetectorGroup(const std::vector<IDetector_const_sptr> &dets)
36 : IDetector(), m_id(), m_detectors(), group_topology(undef) {
37 if (dets.empty()) {
38 g_log.error("Illegal attempt to create an empty DetectorGroup");
39 throw std::invalid_argument("Empty DetectorGroup objects are not allowed");
40 }
41 std::vector<IDetector_const_sptr>::const_iterator it;
42 for (it = dets.begin(); it != dets.end(); ++it) {
43 addDetector(*it);
44 }
45}
46
51 // the topology of the group become undefined and needs recalculation if new
52 // detector has been added to the group
54
55 // For now at least, the ID is the same as the first detector that is added
56 if (m_detectors.empty())
57 m_id = det->getID();
58
59 m_detectors.insert(DetCollection::value_type(det->getID(), det));
60}
61
63
64std::size_t DetectorGroup::nDets() const { return m_detectors.size(); }
65
75 V3D newPos;
76 DetCollection::const_iterator it;
77 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
78 newPos += (*it).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
93double DetectorGroup::getDistance(const IComponent &comp) const {
94 double result = 0.0;
95 DetCollection::const_iterator it;
96 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
97 result += (*it).second->getDistance(comp);
98 }
99 return result / static_cast<double>(m_detectors.size());
100}
101
104double DetectorGroup::getTwoTheta(const V3D &observer, const V3D &axis) const {
105 double result = 0.0;
106 DetCollection::const_iterator it;
107 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
108 const V3D sampleDetVec = (*it).second->getPos() - observer;
109 result += sampleDetVec.angle(axis);
110 }
111 return result / static_cast<double>(m_detectors.size());
112}
113
114/*
115Gives the average angle of a group of detectors from the observation point,
116relative to the axis given.
117Returned values are signed according to the rotation direction relative to the
118axis and the instrument up direction.
119@param observer : observer (usually sample)
120@param axis : scattering axis.
121@param instrumentUp : Instrument up direction
122@return signed theta
123*/
124double DetectorGroup::getSignedTwoTheta(const Kernel::V3D &observer, const Kernel::V3D &axis,
125 const Kernel::V3D &instrumentUp) const {
126 double result = 0.0;
127 DetCollection::const_iterator it;
128 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
129 const V3D sampleDetVec = it->second->getPos() - observer;
130 double angle = sampleDetVec.angle(axis);
131
132 V3D cross = axis.cross_prod(sampleDetVec);
133 V3D normToSurface = axis.cross_prod(instrumentUp);
134 if (normToSurface.scalar_prod(cross) < 0) {
135 angle *= -1;
136 }
137 result += angle;
138 }
139 return result / static_cast<double>(m_detectors.size());
140}
141
143double DetectorGroup::getPhi() const {
144 V3D avgPos = this->getPos();
145 double phi(0.0), dummy1(0.0), dummy2(0.0);
146 avgPos.getSpherical(dummy1, dummy2, phi);
147 return phi * M_PI / 180.0;
148}
149
151double DetectorGroup::getPhiOffset(const double &offset) const {
152 double avgPos = getPhi();
153 return avgPos < 0 ? -(offset + avgPos) : offset - avgPos;
154}
155
160std::vector<detid_t> DetectorGroup::getDetectorIDs() const {
161 std::vector<detid_t> result;
162 result.reserve(m_detectors.size());
163 DetCollection::const_iterator it;
164 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
165 result.emplace_back((*it).first);
166 }
167 return result;
168}
169
174std::vector<IDetector_const_sptr> DetectorGroup::getDetectors() const {
175 std::vector<IDetector_const_sptr> result;
176 result.reserve(m_detectors.size());
177 DetCollection::const_iterator it;
178 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
179 result.emplace_back((*it).second);
180 }
181 return result;
182}
183
191double DetectorGroup::solidAngle(const V3D &observer) const {
192 double result =
193 std::accumulate(m_detectors.cbegin(), m_detectors.cend(), 0.0,
194 [&observer](double angle, const auto &det) { return angle + det.second->solidAngle(observer); });
195 return result;
196}
197
202 DetCollection::const_iterator it;
203 for (it = m_detectors.begin(); it != m_detectors.end(); ++it)
204 if ((*it).second->isParametrized())
205 return true;
206 return false;
207}
208
215bool DetectorGroup::isValid(const V3D &point) const {
216 DetCollection::const_iterator it;
217 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
218 if ((*it).second->isValid(point))
219 return true;
220 }
221 return false;
222}
223
229bool DetectorGroup::isOnSide(const V3D &point) const {
230 DetCollection::const_iterator it;
231 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
232 if ((*it).second->isOnSide(point))
233 return true;
234 }
235 return false;
236}
237
246 DetCollection::const_iterator it;
247 it = m_detectors.begin();
248 if (it == m_detectors.end())
249 return 0;
250 return (*m_detectors.begin()).second->getPointInObject(point);
251}
252
259std::set<std::string> DetectorGroup::getParameterNames(bool recursive) const {
260 (void)recursive; // Avoid compiler warning
261 return std::set<std::string>();
262}
263
270std::map<std::string, ComponentID> DetectorGroup::getParameterNamesByComponent() const {
271 return std::map<std::string, ComponentID>();
272}
273
281std::string DetectorGroup::getParameterAsString(const std::string &pname, bool recursive) const {
282 (void)pname; // Avoid compiler warning
283 (void)recursive; // Avoid compiler warning
284 return "";
285}
286
294bool DetectorGroup::getParameterVisible(const std::string &pname, bool recursive) const {
295 (void)pname; // Avoid compiler warning
296 (void)recursive; // Avoid compiler warning
297 return false;
298}
299
306 // boundingBox = BoundingBox(); // this change may modify a lot of behaviour
307 // -> verify
308 for (const auto &detector : m_detectors) {
309 BoundingBox memberBox;
310 if (!boundingBox.isAxisAligned()) {
311 // coordinate system
312 const std::vector<V3D> *cs = &(boundingBox.getCoordSystem());
313 memberBox.realign(cs);
314 }
315 detector.second->getBoundingBox(memberBox);
316 boundingBox.grow(memberBox);
317 }
318}
327bool DetectorGroup::hasParameter(const std::string &name, bool recursive) const {
328 (void)recursive; // Avoid compiler warning
329 (void)name; // Avoid compiler warning
330 return false;
331}
333std::string DetectorGroup::getParameterType(const std::string & /*name*/, bool /*recursive = true*/) const {
334 return std::string("");
335}
336
338std::vector<double> DetectorGroup::getNumberParameter(const std::string & /*pname*/, bool /*recursive*/) const {
339 return std::vector<double>(0);
340}
341
343std::vector<V3D> DetectorGroup::getPositionParameter(const std::string & /*pname*/, bool /*recursive*/) const {
344 return std::vector<V3D>(0);
345}
346
348std::vector<Quat> DetectorGroup::getRotationParameter(const std::string & /*pname*/, bool /*recursive*/) const {
349 return std::vector<Quat>(0);
350}
351
353std::vector<std::string> DetectorGroup::getStringParameter(const std::string & /*pname*/, bool /*recursive*/) const {
354 return std::vector<std::string>(0);
355}
356
358std::vector<int> DetectorGroup::getIntParameter(const std::string & /*pname*/, bool /*recursive*/) const {
359 return std::vector<int>(0);
360}
361
363std::vector<bool> DetectorGroup::getBoolParameter(const std::string & /*pname*/, bool /*recursive*/) const {
364 return std::vector<bool>(0);
365}
366
369 if (group_topology == undef) {
371 }
372 center = this->groupCentre;
373 return group_topology;
374}
382 if (m_detectors.size() == 1) {
384
385 return;
386 }
387 this->groupCentre = this->getPos();
388 if (this->isValid(groupCentre)) {
390 } else {
391 // the topology can still be rectangular, but randomisation errors or small
392 // gaps between
393 // detectors caused central point not to belong to detectors; need more
394 // accrurate estinations
395 // assuming that distance between detectors can not be bigger then
396 // detector's half size
397 // get detector's size:
398 IDetector_const_sptr spFirstDet = this->m_detectors.begin()->second;
399
400 BoundingBox bbox;
401 spFirstDet->getBoundingBox(bbox);
402 V3D width = bbox.width();
403
404 // loop if any near point belongs to group;
405 for (int i = 0; i < 6; i++) {
406 int ic = int(i) / 2;
407 int is = (i % 2 == 0) ? -1 : 1;
408 V3D cs = groupCentre;
409 cs[ic] += is * width[ic] / 4;
410 if (this->isValid(cs)) { // if it is, finish and end
412 break;
413 }
414 }
415 // if not, consider this group to be a ring;
416 if (this->group_topology == undef) {
418 }
419 }
420}
421
422std::string DetectorGroup::getName() const {
423 std::string result;
424 DetCollection::const_iterator it;
425 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
426 result += (*it).second->getName() + this->getNameSeparator();
427 }
428 return result;
429}
430
431std::string DetectorGroup::getFullName() const {
432 std::string result;
433 DetCollection::const_iterator it;
434 for (it = m_detectors.begin(); it != m_detectors.end(); ++it) {
435 result += (*it).second->getFullName() + this->getNameSeparator();
436 }
437 return result;
438}
439
441
444 throw std::runtime_error("A DetectorGroup cannot have a ParameterMap");
445}
446
448size_t DetectorGroup::index() const { throw std::runtime_error("A DetectorGroup cannot have an index"); }
449
450size_t DetectorGroup::registerContents(class ComponentVisitor & /*component*/) const {
451 throw std::runtime_error("DetectorGroup::registerContents. This should not "
452 "be called. DetectorGroups are not part of the "
453 "instrument. On-the-fly only.");
454}
455
456} // namespace Mantid::Geometry
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition: BoundingBox.h:34
std::vector< Kernel::V3D > const & getCoordSystem() const
returns the coordinate system to which BB is alighned to;
Definition: BoundingBox.h:118
Kernel::V3D width() const
Returns the width of the box.
Definition: BoundingBox.h:98
bool isAxisAligned() const
Check if it is normal axis aligned bounding box or not.
Definition: BoundingBox.h:116
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
double solidAngle(const Kernel::V3D &observer) const override
Gives the total solid angle subtended by a group of detectors by summing the contributions from the i...
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 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::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:51
Interface class for detector objects.
Definition: IDetector.h:43
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
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:274
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Definition: V3D.h:278
double angle(const V3D &) const
Angle between this and another vector.
Definition: V3D.cpp:165
void getSpherical(double &R, double &theta, double &phi) const noexcept
Return the vector's position in spherical coordinates.
Definition: V3D.cpp:117
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.
Definition: SpectrumInfo.h:21