Mantid
Loading...
Searching...
No Matches
CloneMatrixWorkspace.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 +
7//-----------------------------------------------------------------------------
8// Includes
9//-----------------------------------------------------------------------------
13
14#include <boost/python/errors.hpp>
15#include <boost/python/extract.hpp>
16
17#include <stdexcept>
18
19// See
20// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PY_ARRAY_UNIQUE_SYMBOL
21#define PY_ARRAY_UNIQUE_SYMBOL API_ARRAY_API
22#define NO_IMPORT_ARRAY
23#include <numpy/arrayobject.h>
24
28
29// ----------------------------------------------------------------------------------------------------------
30namespace {
32enum DataField { XValues = 0, YValues = 1, EValues = 2, DxValues = 3 };
33
41template <DataField Field> decltype(auto) fieldData(MatrixWorkspace const &workspace, size_t const index) {
44 throw std::logic_error("fieldData does not handle this DataField");
45}
46
47template <> decltype(auto) fieldData<XValues>(MatrixWorkspace const &workspace, size_t const index) {
48 return workspace.x(index);
49}
50
51template <> decltype(auto) fieldData<YValues>(MatrixWorkspace const &workspace, size_t const index) {
52 return workspace.y(index);
53}
54
55template <> decltype(auto) fieldData<EValues>(MatrixWorkspace const &workspace, size_t const index) {
56 return workspace.e(index);
57}
58
59template <> decltype(auto) fieldData<DxValues>(MatrixWorkspace const &workspace, size_t const index) {
60 return workspace.dx(index);
61}
62
70template <DataField Field> size_t fieldSize(MatrixWorkspace const &workspace, size_t const index) {
73 throw std::logic_error("fieldSize does not handle this DataField");
74}
75
76template <> size_t fieldSize<XValues>(MatrixWorkspace const &workspace, size_t const index) {
77 return workspace.x(index).size();
78}
79
80template <> size_t fieldSize<YValues>(MatrixWorkspace const &workspace, size_t const index) {
81 return workspace.histogramSize(index);
82}
83
84template <> size_t fieldSize<EValues>(MatrixWorkspace const &workspace, size_t const index) {
85 return workspace.histogramSize(index);
86}
87
88template <> size_t fieldSize<DxValues>(MatrixWorkspace const &workspace, size_t const index) {
89 return workspace.dx(index).size();
90}
91
101template <DataField Field>
102PyArrayObject *cloneArray(MatrixWorkspace const &workspace, size_t const start, size_t const endp1) {
103 npy_intp const numHist(endp1 - start);
104 npy_intp const stride = numHist > 0 ? static_cast<npy_intp>(fieldSize<Field>(workspace, start)) : 0;
105
106 // For numpy 2D array ensure all spectra have same number of values
107 for (npy_intp i = 1; i < numHist; ++i) {
108 if (static_cast<npy_intp>(fieldSize<Field>(workspace, start + i)) != stride) {
109 throw std::length_error("Cannot extract data from a ragged workspace: the histograms do not all have the same "
110 "number of values.");
111 }
112 }
113
114 npy_intp arrayDims[2] = {numHist, stride};
115 auto *nparray =
116 reinterpret_cast<PyArrayObject *>(PyArray_NewFromDescr(&PyArray_Type, PyArray_DescrFromType(NPY_DOUBLE),
117 2, // rank 2
118 arrayDims, // Length in each dimension
119 nullptr, nullptr, 0, nullptr));
120 // prevent segfault by ensuring that the array was created successfully
121 // otherwise, numpy has set the error indicator already, e.g. MemoryError for a workspace too large to fit
122 if (nparray == nullptr) {
123 throw boost::python::error_already_set();
124 }
125 auto *dest = reinterpret_cast<double *>(PyArray_DATA(nparray)); // HEAD of the contiguous numpy data array
126
128 for (npy_intp i = 0; i < numHist; ++i) {
129 auto const &src = fieldData<Field>(workspace, start + i);
130 std::copy(src.begin(), src.end(), std::next(dest, i * stride));
131 }
132 return nparray;
133}
134} // namespace
135
136// -------------------------------------- Cloned
137// arrays---------------------------------------------------
138/* Create a numpy array from the X values of the given workspace reference
139 * This acts like a python method on a Matrixworkspace object
140 * @param self :: A pointer to a PyObject representing the calling object
141 * @return A 2D numpy array created from the X values
142 */
143PyObject *cloneX(const MatrixWorkspace &self) {
144 return reinterpret_cast<PyObject *>(cloneArray<XValues>(self, 0, self.getNumberHistograms()));
145}
146/* Create a numpy array from the Y values of the given workspace reference
147 * This acts like a python method on a Matrixworkspace object
148 * @param self :: A pointer to a PyObject representing the calling object
149 * @return A 2D numpy array created from the Y values
150 */
151PyObject *cloneY(const MatrixWorkspace &self) {
152 return reinterpret_cast<PyObject *>(cloneArray<YValues>(self, 0, self.getNumberHistograms()));
153}
154
155/* Create a numpy array from the E values of the given workspace reference
156 * This acts like a python method on a Matrixworkspace object
157 * @param self :: A pointer to a PyObject representing the calling object
158 * @return A 2D numpy array created from the E values
159 */
160PyObject *cloneE(const MatrixWorkspace &self) {
161 return reinterpret_cast<PyObject *>(cloneArray<EValues>(self, 0, self.getNumberHistograms()));
162}
163
164/* Create a numpy array from the E values of the given workspace reference
165 * This acts like a python method on a Matrixworkspace object
166 * @param self :: A pointer to a PyObject representing the calling object
167 * @return A 2D numpy array created from the E values
168 */
169PyObject *cloneDx(const MatrixWorkspace &self) {
170 return reinterpret_cast<PyObject *>(cloneArray<DxValues>(self, 0, self.getNumberHistograms()));
171}
172} // namespace Mantid::PythonInterface
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
tagPyArrayObject PyArrayObject
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
Base MatrixWorkspace Abstract Class.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
PyObject * cloneE(const API::MatrixWorkspace &self)
Create a numpy array from the E values of the given workspace reference.
PyObject * cloneY(const API::MatrixWorkspace &self)
Create a numpy array from the Y values of the given workspace reference.
PyObject * cloneDx(const API::MatrixWorkspace &self)
Create a numpy array from the E values of the given workspace reference.
PyObject * cloneX(const API::MatrixWorkspace &self)