Mantid
Loading...
Searching...
No Matches
PanelsSurfaceCalculator.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2025 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 <boost/python.hpp>
12#include <boost/python/class.hpp>
13#include <boost/python/list.hpp>
14
15// boost::python generates this warning in gcc
16GNU_DIAG_OFF("maybe-uninitialized")
17
18using namespace boost::python;
19
20namespace {
23
24void setupBasisAxes(const PanelsSurfaceCalculator &self, object &xAxis, object &yAxis, const object &zAxis) {
25 auto x = PyObjectToV3D(xAxis)();
26 auto y = PyObjectToV3D(yAxis)();
27 const auto z = PyObjectToV3D(zAxis)();
28 self.setupBasisAxes(z, x, y);
29 for (size_t i = 0; i < 3; i++) {
30 xAxis[i] = x[i];
31 yAxis[i] = y[i];
32 }
33}
34
35list retrievePanelCorners(const PanelsSurfaceCalculator &self, const object &componentInfo, const size_t rootIndex) {
36 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
37 const auto panelCorners = self.retrievePanelCorners(*(cInfoSharedPtr.get()), rootIndex);
38 list panelCornersList;
39 for (size_t i = 0; i < panelCorners.size(); i++) {
40 list corner(panelCorners[i]);
41 panelCornersList.append(corner);
42 }
43 return panelCornersList;
44}
45
46list calculatePanelNormal(const PanelsSurfaceCalculator &self, const object &panelCorners) {
47 if (len(panelCorners) != 4) {
48 throw std::invalid_argument("Must be 4 panel corners");
49 }
50 std::vector<V3D> panelCornersVec{4};
51 for (size_t i = 0; i < 4; i++) {
52 const object corner = panelCorners[i];
53 panelCornersVec[i] = PyObjectToV3D(panelCorners[i])();
54 }
55 const auto panelNormal = self.calculatePanelNormal(panelCornersVec);
56 list panelNormalList(panelNormal);
57 return panelNormalList;
58}
59
60bool isBankFlat(PanelsSurfaceCalculator &self, const object &componentInfo, const size_t bankIndex, const list &tubes,
61 const object &normal) {
62 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
63 std::vector<size_t> tubesVector;
64 const size_t lenTubes = len(tubes);
65 for (size_t i = 0; i < lenTubes; i++) {
66 tubesVector.push_back(extract<size_t>(tubes[i]));
67 }
68 const auto normalV3D = PyObjectToV3D(normal)();
69 return self.isBankFlat(*(cInfoSharedPtr.get()), bankIndex, tubesVector, normalV3D);
70}
71
72list calculateBankNormal(PanelsSurfaceCalculator &self, const object &componentInfo, const list &tubes) {
73 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
74 std::vector<size_t> tubesVector;
75 const size_t lenTubes = len(tubes);
76 for (size_t i = 0; i < lenTubes; i++) {
77 tubesVector.push_back(extract<size_t>(tubes[i]));
78 }
79 const auto normal = self.calculateBankNormal(*(cInfoSharedPtr.get()), tubesVector);
80 list normalList{normal};
81 return normalList;
82}
83
84void setBankVisited(const PanelsSurfaceCalculator &self, const object &componentInfo, const size_t bankIndex,
85 list &visitedComponents) {
86 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
87 std::vector<bool> visitedComponentsVector;
88 const size_t lenVisitedComponents = len(visitedComponents);
89 for (size_t i = 0; i < lenVisitedComponents; i++) {
90 visitedComponentsVector.push_back(extract<bool>(visitedComponents[i]));
91 }
92 self.setBankVisited(*(cInfoSharedPtr.get()), bankIndex, visitedComponentsVector);
93 for (size_t i = 0; i < lenVisitedComponents; i++) {
94 // A bool is 8 bytes because a byte is the smallest addressable unit of memory, but
95 // an std::vector<bool> uses bits to store bools as a memory optimisation. Hence
96 // the objects in a vector<bool> are not actually bools, and boost::python
97 // doesn't know what to do with them
98 visitedComponents[i] = visitedComponentsVector[i] ? true : false;
99 }
100}
101
102size_t findNumDetectors(const PanelsSurfaceCalculator &self, const object &componentInfo, const list &components) {
103 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
104 std::vector<size_t> componentsVector;
105 const size_t lenComponents = len(components);
106 for (size_t i = 0; i < lenComponents; i++) {
107 componentsVector.push_back(extract<size_t>(components[i]));
108 }
109 return self.findNumDetectors(*(cInfoSharedPtr.get()), componentsVector);
110}
111
112list calcBankRotation(const PanelsSurfaceCalculator &self, const object &detPos, object normal, const object &zAxis,
113 const object &yAxis, const object &samplePosition) {
114 const auto bankRotation =
115 self.calcBankRotation(PyObjectToV3D(detPos)(), PyObjectToV3D(normal)(), PyObjectToV3D(zAxis)(),
116 PyObjectToV3D(yAxis)(), PyObjectToV3D(samplePosition)());
117
118 list quat;
119 quat.append(bankRotation.real());
120 quat.append(bankRotation.imagI());
121 quat.append(bankRotation.imagJ());
122 quat.append(bankRotation.imagK());
123 return quat;
124}
125
126list transformedBoundingBoxPoints(const PanelsSurfaceCalculator &self, const object &componentInfo,
127 size_t detectorIndex, const object &refPos, const list &rotation, const object &xaxis,
128 const object &yaxis) {
129 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
130 Mantid::Kernel::Quat quatRotation{extract<double>(rotation[0]), extract<double>(rotation[1]),
131 extract<double>(rotation[2]), extract<double>(rotation[3])};
132 const auto referencePosition = PyObjectToV3D(refPos)();
133 const auto xAxisVec = PyObjectToV3D(xaxis)();
134 const auto yAxisVec = PyObjectToV3D(yaxis)();
135 const auto boundingBoxPoints = self.transformedBoundingBoxPoints(*(cInfoSharedPtr.get()), detectorIndex,
136 referencePosition, quatRotation, xAxisVec, yAxisVec);
137 list pointA, pointB;
138 pointA.append(boundingBoxPoints[0].X());
139 pointA.append(boundingBoxPoints[0].Y());
140 pointB.append(boundingBoxPoints[1].X());
141 pointB.append(boundingBoxPoints[1].Y());
142 list result;
143 result.append(pointA);
144 result.append(pointB);
145 return result;
146}
147
148list getAllTubeDetectorFlatGroupParents(PanelsSurfaceCalculator &self, const object &componentInfo) {
149 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
150 const auto allTubeGroupParents =
151 self.examineAllComponents(*(cInfoSharedPtr.get()), [&](const auto &cinfo, auto root, auto &visited) {
152 return self.tubeDetectorParentIDs(cinfo, root, visited);
153 });
154 list pyAllTubeGroupParents;
155 for (size_t groupIndex = 0; groupIndex < allTubeGroupParents.size(); groupIndex++) {
156 const auto tubeGroupParents = allTubeGroupParents[groupIndex];
157 list pyTubeGroupParents;
158 for (size_t tubeParentIndex = 0; tubeParentIndex < tubeGroupParents.size(); tubeParentIndex++) {
159 pyTubeGroupParents.append(tubeGroupParents[tubeParentIndex]);
160 }
161 pyAllTubeGroupParents.append(pyTubeGroupParents);
162 }
163 return pyAllTubeGroupParents;
164}
165
166tuple getSideBySideViewPos(const PanelsSurfaceCalculator &self, const object &componentInfo, const object &instrument,
167 const size_t componentIndex) {
168 const std::shared_ptr<ComponentInfo> cInfoSharedPtr = extract<std::shared_ptr<ComponentInfo>>(componentInfo);
169 const std::shared_ptr<Instrument> instrumentSharedPtr = extract<std::shared_ptr<Instrument>>(instrument);
170 const auto sideBySidePos = self.getSideBySideViewPos(*(cInfoSharedPtr).get(), instrumentSharedPtr, componentIndex);
171 list position;
172 list result;
173 if (!sideBySidePos.has_value()) {
174 position.append(0);
175 position.append(0);
176 result.append(false);
177 } else {
178 position.append(sideBySidePos->X());
179 position.append(sideBySidePos->Y());
180 result.append(true);
181 }
182 result.append(position);
183 return tuple(result);
184}
185
186} // namespace
187
189 using namespace boost::python;
191
192 class_<PanelsSurfaceCalculator, boost::noncopyable>("PanelsSurfaceCalculator",
193 init<>("Make a side by side projection calculator"))
194 .def("setupBasisAxes", &setupBasisAxes, (arg("self"), arg("xaxis"), arg("yaxis"), arg("zaxis")),
195 "Sets up the basis axes for the projection.")
196 .def("retrievePanelCorners", &retrievePanelCorners, (arg("self"), arg("componentInfo"), arg("rootIndex")),
197 "Retrieves the corners of the panel.")
198 .def("calculatePanelNormal", &calculatePanelNormal, (arg("self"), arg("panelCorners")),
199 "Calculates the normal vector of the panel.")
200 .def("isBankFlat", &isBankFlat,
201 (arg("self"), arg("componentInfo"), arg("bankIndex"), arg("tubes"), arg("normal")),
202 "Checks if a bank is flat based on its normal vector.")
203 .def("calculateBankNormal", &calculateBankNormal, (arg("self"), arg("componentInfo"), arg("tubes")),
204 "Calculates the normal vector of a bank.")
205 .def("setBankVisited", &setBankVisited,
206 (arg("self"), arg("componentInfo"), arg("bankIndex"), arg("visitedComponents")),
207 "Marks a bank as visited in the visitedComponents vector")
208 .def("findNumDetectors", &findNumDetectors, (arg("componentInfo"), arg("components")),
209 "Finds the number of detectors in a component.")
210 .def("calcBankRotation", &calcBankRotation,
211 (arg("self"), arg("detPos"), arg("normal"), arg("zAxis"), arg("yAxis"), arg("samplePosition")),
212 "Calculates the rotation quaternion for a bank based on its position and normal vector.")
213 .def("transformedBoundingBoxPoints", &transformedBoundingBoxPoints,
214 (arg("self"), arg("componentInfo"), arg("detectorIndex"), arg("refPos"), arg("rotation"), arg("xaxis"),
215 arg("yaxis")),
216 "Transforms a component's bounding box based on reference position and rotation. The rotation should be "
217 "provided as a list containing the real and imaginary parts of a quaternion (w, i, j, k).")
218 .def("getAllTubeDetectorFlatGroupParents", &getAllTubeDetectorFlatGroupParents,
219 (arg("self"), arg("componentInfo")),
220 "Returns the parent component indices of detectors of all groups of tubes arranged in flat banks")
221 .def("getSideBySideViewPos", &getSideBySideViewPos,
222 (arg("self"), arg("componentInfo"), arg("instrument"), arg("componentIndex")),
223 "Returns a tuple indicating whether the bank side-by-side projection position has been specified in the "
224 "IDF, and what it is.");
225}
double position
Definition GetAllEi.cpp:154
IntArray detectorIndex
void export_PanelsSurfaceCalculator()
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
Class for quaternions.
Definition Quat.h:39
Takes a Python object and if it supports indexing and is of length 3 then it will attempt to convert ...