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>
25#define PY_ARRAY_UNIQUE_SYMBOL GEOMETRY_ARRAY_API
26#define NO_IMPORT_ARRAY
27#include <numpy/ndarrayobject.h>
32using Mantid::PythonInterface::DetectorInfoPythonIterator;
42 return DetectorInfoPythonIterator(detectorInfo);
47 return observer.is_none() ? self.
samplePosition() : extract<V3D>(observer)();
53 return extract<V3D>(axis)();
55 if (beamLine.nullVector())
61 if (observer.is_none() && axis.is_none())
63 return self.
twoTheta(
index, observerOrSample(self, observer), axisOrBeam(self, axis));
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())
70 if (instrumentUp.is_none())
71 return self.
signedTwoTheta(
index, observerOrSample(self, observer), axisOrBeam(self, axis));
73 extract<V3D>(instrumentUp)());
76using return_readonly_numpy = return_value_policy<Policies::VectorRefToNumpy<Converters::WrapReadOnly>>;
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);
84 PyErr_SetString(PyExc_RuntimeError,
"Failed to create numpy array");
85 throw boost::python::error_already_set();
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();
99 return numpyArrayFromVector(positions);
104 return numpyArrayFromVector(positions);
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();
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();
125 return numpy_rotations_array;
153 class_<DetectorInfo, boost::noncopyable>(
"DetectorInfo", no_init)
158 "Returns the size of the DetectorInfo, i.e., the number of "
159 "detectors in the instrument.")
162 "Returns the size of the DetectorInfo, i.e., the number of "
163 "detectors in the instrument.")
166 "Returns the index of the detector with the given id.")
169 "Returns the detector id of the detector identified by 'index'.")
171 .def(
"isMonitor", isMonitor, (arg(
"self"), arg(
"index")),
"Returns True if the detector is a monitor.")
173 .def(
"isMasked", isMasked, (arg(
"self"), arg(
"index")),
"Returns True if the detector is masked.")
175 .def(
"setMasked", setMasked, (arg(
"self"), arg(
"index"), arg(
"masked")),
176 "Set the mask flag of the detector where the detector is identified "
182 "Returns True if the content of this "
183 "detector is equivalent to the content "
184 "of the other detector.")
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 "
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 "
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.")
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")
222 "Returns if there are masked detectors")
224 "Return the memory footprint of the detector info in bytes.");
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.