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 +
11#include "MantidKernel/Quat.h"
12#include "MantidKernel/V3D.h"
15#include "MantidPythonInterface/geometry/DetectorInfoPythonIterator.h"
16#include <boost/iterator/iterator_facade.hpp>
17#include <boost/python/class.hpp>
18#include <boost/python/copy_const_reference.hpp>
19#include <boost/python/copy_non_const_reference.hpp>
20#include <boost/python/iterator.hpp>
21#include <boost/python/return_by_value.hpp>
22#include <boost/python/return_value_policy.hpp>
23#include <iterator>
24
25#define PY_ARRAY_UNIQUE_SYMBOL GEOMETRY_ARRAY_API
26#define NO_IMPORT_ARRAY
27#include <numpy/ndarrayobject.h>
28
32using Mantid::PythonInterface::DetectorInfoPythonIterator;
33
36using namespace boost::python;
37using namespace Mantid::PythonInterface;
38
39namespace {
40// Helper method to make the python iterator
41DetectorInfoPythonIterator make_pyiterator(DetectorInfo &detectorInfo) {
42 return DetectorInfoPythonIterator(detectorInfo);
43}
44
46V3D observerOrSample(const DetectorInfo &self, const object &observer) {
47 return observer.is_none() ? self.samplePosition() : extract<V3D>(observer)();
48}
49
51V3D axisOrBeam(const DetectorInfo &self, const object &axis) {
52 if (!axis.is_none())
53 return extract<V3D>(axis)();
54 const auto beamLine = self.samplePosition() - self.sourcePosition();
55 if (beamLine.nullVector())
56 throw Mantid::Kernel::Exception::InstrumentDefinitionError("Source and sample are at same position!");
57 return beamLine;
58}
59
60double twoTheta(const DetectorInfo &self, const size_t index, const object &observer, const object &axis) {
61 if (observer.is_none() && axis.is_none())
62 return self.twoTheta(index);
63 return self.twoTheta(index, observerOrSample(self, observer), axisOrBeam(self, axis));
64}
65
66double signedTwoTheta(const DetectorInfo &self, const size_t index, const object &observer, const object &axis,
67 const object &instrumentUp) {
68 if (observer.is_none() && axis.is_none() && instrumentUp.is_none())
69 return self.signedTwoTheta(index);
70 if (instrumentUp.is_none())
71 return self.signedTwoTheta(index, observerOrSample(self, observer), axisOrBeam(self, axis));
72 return self.signedTwoTheta(index, observerOrSample(self, observer), axisOrBeam(self, axis),
73 extract<V3D>(instrumentUp)());
74}
76using return_readonly_numpy = return_value_policy<Policies::VectorRefToNumpy<Converters::WrapReadOnly>>;
77
78PyObject *numpyArrayFromVector(const std::vector<V3D> &vec) {
79 const size_t n_detectors = vec.size();
80 constexpr size_t vec_size = 3;
81 npy_intp dims[2] = {static_cast<npy_intp>(n_detectors), vec_size};
82 PyObject *numpy_array = PyArray_SimpleNew(2, dims, NPY_DOUBLE);
83 if (!numpy_array) {
84 PyErr_SetString(PyExc_RuntimeError, "Failed to create numpy array");
85 throw boost::python::error_already_set();
86 }
87 double *data = static_cast<double *>(PyArray_DATA(reinterpret_cast<PyArrayObject *>(numpy_array)));
88 for (size_t i = 0; i < n_detectors; ++i) {
89 const size_t base_index = i * vec_size;
90 data[base_index + 0] = vec[i].X();
91 data[base_index + 1] = vec[i].Y();
92 data[base_index + 2] = vec[i].Z();
93 }
94 return numpy_array;
95}
96
97PyObject *allPositions(const DetectorInfo &self) {
98 const std::vector<V3D> positions = self.allPositions();
99 return numpyArrayFromVector(positions);
100}
101
102PyObject *allScaleFactors(const DetectorInfo &self) {
103 const std::vector<V3D> positions = self.allScaleFactors();
104 return numpyArrayFromVector(positions);
105}
106
107PyObject *allRotations(const DetectorInfo &self) {
108 const std::vector<Quat> rotations = self.allRotations();
109 const size_t n_detectors = rotations.size();
110 const size_t quat_size = 4;
111 npy_intp dims[2] = {static_cast<npy_intp>(n_detectors), quat_size};
112 PyObject *numpy_rotations_array = PyArray_SimpleNew(2, dims, NPY_DOUBLE);
113 if (!numpy_rotations_array) {
114 PyErr_SetString(PyExc_RuntimeError, "Failed to create numpy array");
115 throw boost::python::error_already_set();
116 }
117 double *data = static_cast<double *>(PyArray_DATA(reinterpret_cast<PyArrayObject *>(numpy_rotations_array)));
118 for (size_t i = 0; i < n_detectors; ++i) {
119 const size_t base_index = i * quat_size;
120 data[base_index + 0] = rotations[i].imagI();
121 data[base_index + 1] = rotations[i].imagJ();
122 data[base_index + 2] = rotations[i].imagK();
123 data[base_index + 3] = rotations[i].real();
124 }
125 return numpy_rotations_array;
126}
127
128} // namespace
129
130// Export DetectorInfo
132
133 // Function pointers to distinguish between overloaded versions
134 bool (DetectorInfo::*isMonitor)(const size_t) const = &DetectorInfo::isMonitor;
135
136 bool (DetectorInfo::*isMasked)(const size_t) const = &DetectorInfo::isMasked;
137
138 double (DetectorInfo::*azimuthal)(const size_t) const = &DetectorInfo::azimuthal;
139
140 double (DetectorInfo::*phi)(const size_t) const = &DetectorInfo::phi;
141
142 double (DetectorInfo::*phiOffset)(const size_t, const double) const = &DetectorInfo::phiOffset;
143
145
147
148 void (DetectorInfo::*setMasked)(const size_t, bool) = &DetectorInfo::setMasked;
149
150 double (DetectorInfo::*l2)(const size_t) const = &DetectorInfo::l2;
151
152 // Export to Python
153 class_<DetectorInfo, boost::noncopyable>("DetectorInfo", no_init)
154
155 .def("__iter__", make_pyiterator)
156
157 .def("__len__", &DetectorInfo::size, (arg("self")),
158 "Returns the size of the DetectorInfo, i.e., the number of "
159 "detectors in the instrument.")
160
161 .def("size", &DetectorInfo::size, (arg("self")),
162 "Returns the size of the DetectorInfo, i.e., the number of "
163 "detectors in the instrument.")
164
165 .def("indexOf", &DetectorInfo::indexOf, (arg("self"), arg("detId")),
166 "Returns the index of the detector with the given id.")
167
168 .def("detid", &DetectorInfo::detid, (arg("self"), arg("index")),
169 "Returns the detector id of the detector identified by 'index'.")
170
171 .def("isMonitor", isMonitor, (arg("self"), arg("index")), "Returns True if the detector is a monitor.")
172
173 .def("isMasked", isMasked, (arg("self"), arg("index")), "Returns True if the detector is masked.")
174
175 .def("setMasked", setMasked, (arg("self"), arg("index"), arg("masked")),
176 "Set the mask flag of the detector where the detector is identified "
177 "by 'index'.")
178
179 .def("clearMaskFlags", &DetectorInfo::clearMaskFlags, (arg("self")), "Sets all mask flags to false (unmasked).")
180
181 .def("isEquivalent", &DetectorInfo::isEquivalent, (arg("self"), arg("other")),
182 "Returns True if the content of this "
183 "detector is equivalent to the content "
184 "of the other detector.")
185
186 .def("twoTheta", &twoTheta, (arg("self"), arg("index"), arg("observer") = object(), arg("axis") = object()),
187 "Returns the angle in radians between the vector from the observer to the detector and the axis. The "
188 "observer defaults to the sample position and the axis to the beam direction, giving the scattering "
189 "angle 2 theta. With both defaults, monitors raise an error.")
190 .def("signedTwoTheta", &signedTwoTheta,
191 (arg("self"), arg("index"), arg("observer") = object(), arg("axis") = object(),
192 arg("instrumentUp") = object()),
193 "Returns the signed angle in radians between the vector from the observer to the detector and the axis. "
194 "The observer defaults to the sample position, the axis to the beam direction and instrumentUp to the "
195 "instrument's theta-sign axis, giving the signed scattering angle 2 theta. With all defaults, monitors "
196 "raise an error.")
197 .def("azimuthal", azimuthal, (arg("self"), arg("index")),
198 "Returns the out-of-plane angle in radians angle w.r.t. to "
199 "vecPointingHorizontal")
200 .def("phi", phi, (arg("self"), arg("index")),
201 "Returns the angle in radians of the detector position about the lab-frame z axis, atan2(y, x).")
202 .def("phiOffset", phiOffset, (arg("self"), arg("index"), arg("offset")),
203 "Returns phi reflected about the offset (radians): offset - phi for phi >= 0, otherwise "
204 "-(offset + phi).")
205 .def("position", position, (arg("self"), arg("index")),
206 "Returns the absolute position of the detector where the detector "
207 "is identified by 'index'.")
208 .def("allPositions", &allPositions, (arg("self")),
209 "Returns the absolute positions of all detectors as a numpy array.")
210 .def("rotation", rotation, (arg("self"), arg("index")),
211 "Returns the absolute rotation of the detector where the detector "
212 "is identified by 'index'.")
213 .def("allRotations", &allRotations, (arg("self")),
214 "Returns the absolute rotations of all detectors as a numpy array of quarternions, [i, j, k, w].")
215 .def("allScaleFactors", &allScaleFactors, (arg("self")),
216 "Returns the scale factors of all detectors as a numpy array.")
217 .def("detectorIDs", &DetectorInfo::detectorIDs, return_readonly_numpy(),
218 "Returns all detector ids sorted by detector index")
219 .def("l2", l2, (arg("self"), arg("index")), "Returns the l2 scattering distance")
220 .def("l1", &DetectorInfo::l1, arg("self"), "Returns the l1 scattering distance")
221 .def("hasMaskedDetectors", &DetectorInfo::hasMaskedDetectors, arg("self"),
222 "Returns if there are masked detectors")
223 .def("getMemorySize", &DetectorInfo::getMemorySize, arg("self"),
224 "Return the memory footprint of the detector info in bytes.");
225}
double position
Definition GetAllEi.cpp:154
std::map< DeltaEMode::Type, std::string > index
tagPyArrayObject PyArrayObject
std::vector< T > const * vec
SpectrumInfoPythonIterator make_pyiterator(SpectrumInfo &spectrumInfo)
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
void export_DetectorInfo()
DetectorInfoIterator for random access iteration over DetectorInfo.
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
double twoTheta(const size_t index) const
Returns 2 theta (scattering angle w.r.t. to beam direction).
double l2(const size_t index) const
Returns L2 (distance from sample to spectrum).
std::vector< Kernel::Quat > allRotations() const
Returns the absolute rotations of all detectors in a vector ordered by index.
Kernel::V3D samplePosition() const
Returns the sample position.
double phiOffset(const size_t index, const double offset) const
Returns phi() reflected about offset (radians): offset - phi for phi >= 0 and -(offset + phi) otherwi...
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.
std::vector< Kernel::V3D > allPositions() const
Returns the absolute positions of all detectors in a vector ordered by index.
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.
size_t getMemorySize() const
Return memory used by the detector info, in bytes.
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.
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).
double phi(const size_t index) const
Returns the angle of the detector position about the lab-frame z axis, atan2(y, x),...
Kernel::V3D sourcePosition() const
Returns the source position.
std::vector< Kernel::V3D > allScaleFactors() const
Returns the scale factors of all detectors in a vector ordered by 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.
double azimuthal(const size_t index) const
detid_t detid(const size_t index) const
Returns the detector ID for the given logical detector index.
Exception for errors associated with the instrument definition.
Definition Exception.h:220
Class for quaternions.
Definition Quat.h:38
Class for 3D vectors.
Definition V3D.h:35