Mantid
Loading...
Searching...
No Matches
IPeaksWorkspace.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 +
8#include "MantidAPI/Run.h"
16#include <boost/none.hpp>
17#include <boost/python/class.hpp>
18#include <boost/python/iterator.hpp>
19#include <boost/python/manage_new_object.hpp>
20#include <boost/python/object.hpp>
21#include <boost/python/register_ptr_to_python.hpp>
22#include <boost/python/return_internal_reference.hpp>
23#include <optional>
24#include <utility>
25
26using namespace boost::python;
27using namespace Mantid::Geometry;
28using namespace Mantid::API;
35
37
38namespace {
39
41IPeak *createPeakHKL(const IPeaksWorkspace &self, const object &data) {
43 // Python will manage it
44 return peak.release();
45}
46
48IPeak *createPeakQLab(const IPeaksWorkspace &self, const object &data) {
49 auto peak = self.createPeak(Mantid::PythonInterface::Converters::PyObjectToV3D(data)(), std::nullopt);
50 // Python will manage it
51 return peak.release();
52}
53
55IPeak *createPeakQLabWithDistance(const IPeaksWorkspace &self, const object &data, double detectorDistance) {
56 auto peak = self.createPeak(Mantid::PythonInterface::Converters::PyObjectToV3D(data)(), detectorDistance);
57 // Python will manage the object
58 return peak.release();
59}
60
62IPeak *createPeakQSample(const IPeaksWorkspace &self, const object &data) {
64 // Python will manage it
65 return peak.release();
66}
67
69void addPeak(IPeaksWorkspace &self, const IPeak &peak) {
70 self.addPeak(peak);
71 self.modified();
72}
73
75void addPeak2(IPeaksWorkspace &self, const object &data, const SpecialCoordinateSystem &frame) {
76 self.addPeak(PyObjectToV3D(data)(), frame);
77 self.modified();
78}
79
81void removePeak(IPeaksWorkspace &self, int peak_num) {
82 self.removePeak(peak_num);
83 self.modified();
84}
85
87void removePeaks(IPeaksWorkspace &self, const boost::python::object &peak_nums) {
89 self.modified();
90}
91
99class PeakWorkspaceTableAdaptor {
100public:
106 explicit PeakWorkspaceTableAdaptor(IPeaksWorkspace &peaksWorkspace) : m_peaksWorkspace(peaksWorkspace) {
107 // Create a map of string -> setter functions
108 // Each function will extract the given value from the passed python type.
109 m_setterMap = {{"RunNumber", setterFunction(&IPeak::setRunNumber)},
110 {"h", setterFunction(&IPeak::setH)},
111 {"k", setterFunction(&IPeak::setK)},
112 {"l", setterFunction(&IPeak::setL)},
113 {"Wavelength", setterFunction(&IPeak::setWavelength)},
114 {"Intens", setterFunction(&IPeak::setIntensity)},
115 {"SigInt", setterFunction(&IPeak::setSigmaIntensity)},
116 {"BinCount", setterFunction(&IPeak::setBinCount)},
117 {"PeakNumber", setterFunction(&IPeak::setPeakNumber)},
118 {"QLab", setterFunction(&IPeak::setQLabFrame)},
119 {"QSample", setterFunction(&IPeak::setQSampleFrame)}};
120 }
121
129 void setProperty(const std::string &columnName, const int rowIndex, object value) {
130 auto &peak = m_peaksWorkspace.getPeak(rowIndex);
131 if (m_setterMap.find(columnName) == m_setterMap.end()) {
132 throw std::runtime_error(columnName + " is a read only column of a peaks workspace");
133 }
134 m_setterMap[columnName](peak, std::move(value));
135 }
136
137private:
138 // type alias for the member function to wrap
139 template <typename T> using MemberFunc = void (IPeak::*)(T value);
140 // special type alias for V3D functions that take an addtional parameter
141 using MemberFuncV3D = void (IPeak::*)(const V3D &value, std::optional<double>);
142 // type alias for the setter function
143 using SetterType = std::function<void(IPeak &peak, const object)>;
144
152 template <typename T> SetterType setterFunction(const MemberFunc<T> func) {
153 return [func](IPeak &peak, const object &value) {
154 extract<T> extractor{value};
155 if (!extractor.check()) {
156 throw std::runtime_error("Cannot set value. Value was not of the expected type!");
157 }
158 (peak.*func)(extractor());
159 };
160 }
161
172 SetterType setterFunction(const MemberFuncV3D func) {
173 return [func](IPeak &peak, const object &value) {
174 extract<const V3D &> extractor{value};
175 if (!extractor.check()) {
176 throw std::runtime_error("Cannot set value. Value was not of the expected type!");
177 }
178 (peak.*func)(extractor(), std::nullopt);
179 };
180 }
181
182 // The PeaksWorkspace we need to map value to.
183 IPeaksWorkspace &m_peaksWorkspace;
184 // Map of string value to setter functions.
185 std::unordered_map<std::string, SetterType> m_setterMap;
186};
187
188GNU_DIAG_OFF("maybe-uninitialized")
189
190
200std::pair<int, std::string> getRowAndColumnName(const IPeaksWorkspace &self, const object &col_or_row,
201 const int row_or_col) {
202 extract<std::string> columnNameExtractor{col_or_row};
203 std::string columnName;
204 int rowIndex;
205
206 if (columnNameExtractor.check()) {
207 columnName = columnNameExtractor();
208 rowIndex = row_or_col;
209 } else {
210 rowIndex = extract<int>(col_or_row)();
211 const auto colIndex = row_or_col;
212 const auto columnNames = self.getColumnNames();
213 columnName = columnNames.at(colIndex);
214 }
215
216 return std::make_pair(rowIndex, columnName);
217}
218
219GNU_DIAG_ON("maybe-uninitialized")
220
221
229void setCell(IPeaksWorkspace &self, const object &col_or_row, const int row_or_col, const object &value) {
230 std::string columnName;
231 int rowIndex;
232 std::tie(rowIndex, columnName) = getRowAndColumnName(self, col_or_row, row_or_col);
233
234 PeakWorkspaceTableAdaptor tableMap{self};
235 tableMap.setProperty(columnName, rowIndex, value);
236}
237
240IPeaksWorkspace_sptr extractWorkspace(const object &self) {
241 return std::dynamic_pointer_cast<IPeaksWorkspace>(Mantid::PythonInterface::ExtractSharedPtr<Workspace>(self)());
242}
243
248std::shared_ptr<IPeak> makePeakHandle(const IPeaksWorkspace_sptr &workspace, const int index) {
249 return std::shared_ptr<IPeak>(workspace, workspace->getPeakPtr(index));
250}
251
253std::shared_ptr<IPeak> getPeak(const object &self, const int index) {
254 return makePeakHandle(extractWorkspace(self), index);
255}
256
258struct IPeaksWorkspaceIterator {
259 explicit IPeaksWorkspaceIterator(const IPeaksWorkspace_sptr &workspace)
260 : m_workspace{workspace}, m_numPeaks{workspace->getNumberPeaks()}, m_rowIndex{-1} {
261 assert(workspace);
262 }
263 std::shared_ptr<IPeak> next() {
264 ++m_rowIndex;
265 if (m_rowIndex >= m_numPeaks) {
266 objects::stop_iteration_error();
267 }
268 return makePeakHandle(m_workspace, m_rowIndex);
269 }
270
271private:
272 IPeaksWorkspace_sptr m_workspace;
273 const int m_numPeaks;
274 int m_rowIndex;
275};
276
277// Create an iterator from the given workspace
278IPeaksWorkspaceIterator makePyIterator(const object &self) { return IPeaksWorkspaceIterator(extractWorkspace(self)); }
279
280} // namespace
281
283 class_<IPeaksWorkspaceIterator>("IPeaksWorkspaceIterator", no_init)
284 .def("__next__", &IPeaksWorkspaceIterator::next)
285 .def("__iter__", objects::identity_function());
286}
287
289 // IPeaksWorkspace class
290 class_<IPeaksWorkspace, bases<ITableWorkspace, ExperimentInfo>, boost::noncopyable>("IPeaksWorkspace", no_init)
291 .def("getNumberPeaks", &IPeaksWorkspace::getNumberPeaks, arg("self"),
292 "Returns the number of peaks within the workspace")
293 .def("addPeak", addPeak, (arg("self"), arg("peak")), "Add a peak to the workspace")
294 .def("addPeak", addPeak2, (arg("self"), arg("data"), arg("coord_system")), "Add a peak to the workspace")
295 .def("removePeak", removePeak, (arg("self"), arg("peak_num")), "Remove a peak from the workspace")
296 .def("removePeaks", removePeaks, (arg("self"), arg("peak_num")), "Remove specified peaks from the workspace")
297 .def("getPeak", &getPeak, (arg("self"), arg("peak_num")), "Returns a peak at the given index")
298 .def("createPeak", createPeakQLab, (arg("self"), arg("data")), return_value_policy<manage_new_object>(),
299 "Create a Peak and return it from its coordinates in the QLab frame")
300 .def("createPeak", createPeakQLabWithDistance, (arg("self"), arg("data"), arg("detector_distance")),
301 return_value_policy<manage_new_object>(),
302 "Create a Peak and return it from its coordinates in the QLab "
303 "frame, detector-sample distance explicitly provided")
304 .def("createPeakQSample", createPeakQSample, (arg("self"), arg("data")), return_value_policy<manage_new_object>(),
305 "Create a Peak and return it from its coordinates in the QSample "
306 "frame")
307 .def("createPeakHKL", createPeakHKL, (arg("self"), arg("data")), return_value_policy<manage_new_object>(),
308 "Create a Peak and return it from its coordinates in the HKL frame")
309 .def("hasIntegratedPeaks", &IPeaksWorkspace::hasIntegratedPeaks, arg("self"),
310 "Determine if the peaks have been integrated")
311 .def("getRun", &IPeaksWorkspace::mutableRun, arg("self"), return_internal_reference<>(),
312 "Return the Run object for this workspace")
313 .def("peakInfoNumber", &IPeaksWorkspace::peakInfoNumber, (arg("self"), arg("qlab_frame"), arg("lab_coordinate")),
314 "Peak info number at Q vector for this workspace")
315 .def("setCell", &setCell, (arg("self"), arg("row_or_column"), arg("column_or_row"), arg("value")),
316 "Sets the value of a given cell. If the row_or_column argument is a "
317 "number then it is interpreted as a row otherwise it "
318 "is interpreted as a column name.")
319 .def("__iter__", makePyIterator);
320 //-------------------------------------------------------------------------------------------------
321
323}
double value
The value of the point.
Definition FitMW.cpp:51
#define GET_POINTER_SPECIALIZATION(TYPE)
Definition GetPointer.h:17
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
void export_IPeaksWorkspaceIterator()
void export_IPeaksWorkspace()
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
Interface to the class Mantid::DataObjects::PeaksWorkspace.
virtual bool hasIntegratedPeaks() const =0
Determine if the workspace has been integrated using a peaks integration algorithm.
virtual void removePeak(int peakNum)=0
Removes the indicated peak.
virtual void removePeaks(std::vector< int > badPeaks)=0
virtual void addPeak(const Mantid::Geometry::IPeak &ipeak)=0
Add a peak to the list.
virtual int peakInfoNumber(const Kernel::V3D &qLabFrame, bool labCoords) const =0
virtual std::unique_ptr< Geometry::IPeak > createPeakHKL(const Mantid::Kernel::V3D &HKL) const =0
Create an instance of a peak using a V3D.
virtual std::unique_ptr< Geometry::IPeak > createPeak(const Mantid::Kernel::V3D &QLabFrame, std::optional< double > detectorDistance=std::nullopt) const =0
Create an instance of a Peak.
virtual int getNumberPeaks() const =0
virtual std::unique_ptr< Mantid::Geometry::IPeak > createPeakQSample(const Mantid::Kernel::V3D &position) const =0
Create an instance of a Peak.
void modified()
If the workspace is the AnalysisDataService sends AfterReplaceNotification.
Structure describing a single-crystal peak.
Definition IPeak.h:26
virtual void setIntensity(double m_Intensity)=0
virtual void setK(double m_K)=0
virtual void setBinCount(double m_BinCount)=0
virtual void setQLabFrame(const Mantid::Kernel::V3D &QLabFrame, std::optional< double > detectorDistance)=0
virtual void setH(double m_H)=0
virtual void setPeakNumber(int m_PeakNumber)=0
virtual void setSigmaIntensity(double m_SigmaIntensity)=0
virtual void setL(double m_L)=0
virtual void setRunNumber(int m_RunNumber)=0
virtual void setQSampleFrame(const Mantid::Kernel::V3D &QSampleFrame, std::optional< double > detectorDistance)=0
virtual void setWavelength(double wavelength)=0
Class for 3D vectors.
Definition V3D.h:34
std::shared_ptr< IPeaksWorkspace > IPeaksWorkspace_sptr
shared pointer to Mantid::API::IPeaksWorkspace
std::shared_ptr< Column > Column_sptr
Definition Column.h:232
SpecialCoordinateSystem
Special coordinate systems for Q3D.
STL namespace.
Takes a Python object and if it supports indexing and is of length 3 then it will attempt to convert ...
Converts a Python sequence type to a C++ std::vector, where the element type is defined by the templa...
Encapsulates the registration required for an interface type T that sits on top of a Kernel::DataItem...