BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
ArrayUtils.h
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Device/Intensity/ArrayUtils.h
6 //! @brief Defines various functions to interact from numpy on Python side
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************** //
14 
15 #ifndef BORNAGAIN_CORE_INTENSITY_ARRAYUTILS_H
16 #define BORNAGAIN_CORE_INTENSITY_ARRAYUTILS_H
17 
18 #include "Device/Data/OutputData.h"
19 #include <memory>
20 #include <stdexcept>
21 #include <vector>
22 
23 //! Array and Numpy utility functions getShape, createNumpyArray.
24 
25 namespace ArrayUtils
26 {
27 //! Returns shape nrows, ncols of 2D array.
28 template <class T> std::pair<size_t, size_t> getShape(const T& data);
29 
31 {
32  //! Holds the dimensionality of template argument as the enum value.
33  //! Intended for vectors only.
34  template <typename T> struct nDim {
35  enum { value = 0 };
36  };
37  template <typename T, typename A> struct nDim<std::vector<T, A>> {
38  enum { value = 1 + nDim<T>::value };
39  };
40 
41  template <typename T> struct baseClass {
42  using value = T;
43  };
44  template <typename T, typename A> struct baseClass<std::vector<T, A>> {
45  using value = typename baseClass<T>::value;
46  };
47 
48  template <class T>
49  using ReturnType = std::unique_ptr<OutputData<typename CreateDataImpl::baseClass<T>::value>>;
50 
51  template <class T> friend ReturnType<T> createData(const T& vec);
52 
53  template <class T>
54  static std::unique_ptr<OutputData<T>> createDataImpl(const std::vector<T>& vec);
55 
56  template <class T>
57  static std::unique_ptr<OutputData<T>> createDataImpl(const std::vector<std::vector<T>>& vec);
58 };
59 
60 //! Creates OutputData array from input vector.
61 template <class T> CreateDataImpl::ReturnType<T> createData(const T& vec)
62 {
63  constexpr const int size = CreateDataImpl::nDim<T>::value;
64  static_assert(
65  size == 1 || size == 2,
66  "Error in ArrayUtils::createData: invalid dimensionality or type of the input argument");
67  static_assert(std::is_same<CreateDataImpl::ReturnType<T>,
68  decltype(CreateDataImpl::createDataImpl(vec))>::value,
69  "Error in ArrayUtils::createData: invalid return type.");
71 }
72 
73 #ifdef BORNAGAIN_PYTHON
74 PyObject* createNumpyArray(const std::vector<double>& data);
75 #endif // BORNAGAIN_PYTHON
76 
77 //! Creates 1D vector from OutputData.
78 template <class T> decltype(auto) createVector1D(const T& data);
79 
80 //! Creates 2D vector from OutputData.
81 template <class T> decltype(auto) createVector2D(const T& data);
82 
83 } // namespace ArrayUtils
84 
85 template <class T>
86 std::unique_ptr<OutputData<T>> ArrayUtils::CreateDataImpl::createDataImpl(const std::vector<T>& vec)
87 {
88  auto result = std::make_unique<OutputData<T>>();
89  const size_t length = vec.size();
90  result->addAxis(FixedBinAxis("axis0", length, 0.0, static_cast<double>(length)));
91  result->setRawDataVector(vec);
92  return result;
93 }
94 
95 template <class T>
96 std::unique_ptr<OutputData<T>>
97 ArrayUtils::CreateDataImpl::createDataImpl(const std::vector<std::vector<T>>& vec)
98 {
99  auto result = std::make_unique<OutputData<T>>();
100 
101  auto shape = ArrayUtils::getShape(vec);
102  const size_t nrows = shape.first;
103  const size_t ncols = shape.second;
104 
105  if (nrows == 0 || ncols == 0)
106  throw std::runtime_error(
107  "Error in ArrayUtils::createDataImpl: input argument contains empty dimensions");
108 
109  result->addAxis(FixedBinAxis("axis0", ncols, 0.0, static_cast<double>(ncols)));
110  result->addAxis(FixedBinAxis("axis1", nrows, 0.0, static_cast<double>(nrows)));
111 
112  // filling the data
113  for (size_t row = 0; row < nrows; ++row) {
114  for (size_t col = 0; col < ncols; ++col) {
115  size_t globalbin = nrows - row - 1 + col * nrows;
116  (*result)[globalbin] = vec[row][col];
117  }
118  }
119 
120  return result;
121 }
122 
123 template <class T> std::pair<size_t, size_t> ArrayUtils::getShape(const T& data)
124 {
125  size_t nrows = data.size();
126  size_t ncols(0);
127  if (nrows)
128  ncols = data[0].size();
129  for (size_t row = 0; row < nrows; row++)
130  if (data[row].size() != ncols)
131  throw std::runtime_error("Util::getShape() -> Error. "
132  "Number of elements is different from row to row.");
133  return std::make_pair(nrows, ncols);
134 }
135 
136 template <class T> decltype(auto) ArrayUtils::createVector1D(const T& data)
137 {
138  if (data.getRank() != 1)
139  throw std::runtime_error("ArrayUtils::createVector1D() -> Error. Not 1D data.");
140 
141  using value_type = typename T::value_type;
142  std::vector<value_type> result = data.getRawDataVector();
143  return result;
144 }
145 
146 template <class T> decltype(auto) ArrayUtils::createVector2D(const T& data)
147 {
148  using value_type = typename T::value_type;
149  std::vector<std::vector<value_type>> result;
150 
151  const size_t nrows = data.getAxis(1).size();
152  const size_t ncols = data.getAxis(0).size();
153 
154  result.resize(nrows);
155 
156  for (size_t row = 0; row < nrows; ++row) {
157  result[row].resize(ncols, 0.0);
158  for (size_t col = 0; col < ncols; ++col) {
159  size_t globalbin = nrows - row - 1 + col * nrows;
160  result[row][col] = data[globalbin];
161  }
162  }
163 
164  return result;
165 }
166 
167 #endif // BORNAGAIN_CORE_INTENSITY_ARRAYUTILS_H
Defines and implements template class OutputData.
_object PyObject
Definition: PyObject.h:20
friend ReturnType< T > createData(const T &vec)
Creates OutputData array from input vector.
Definition: ArrayUtils.h:61
std::unique_ptr< OutputData< typename CreateDataImpl::baseClass< T >::value > > ReturnType
Definition: ArrayUtils.h:49
static std::unique_ptr< OutputData< T > > createDataImpl(const std::vector< T > &vec)
Definition: ArrayUtils.h:86
Axis with fixed bin size.
Definition: FixedBinAxis.h:24
Template class to store data of any type in multi-dimensional space.
Definition: OutputData.h:33
Array and Numpy utility functions getShape, createNumpyArray.
Definition: ArrayUtils.h:26
decltype(auto) createVector2D(const T &data)
Creates 2D vector from OutputData.
CreateDataImpl::ReturnType< T > createData(const T &vec)
Creates OutputData array from input vector.
Definition: ArrayUtils.h:61
decltype(auto) createVector1D(const T &data)
Creates 1D vector from OutputData.
std::pair< size_t, size_t > getShape(const T &data)
Returns shape nrows, ncols of 2D array.
Definition: ArrayUtils.h:123
PyObject * createNumpyArray(const std::vector< double > &data)
Definition: ArrayUtils.cpp:20
Holds the dimensionality of template argument as the enum value.
Definition: ArrayUtils.h:34