BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
LLData.h
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/Data/LLData.h
6 //! @brief Defines class LLData.
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 #ifdef SWIG
16 #error no need to expose this header to Swig
17 #endif
18 
19 #ifndef USER_API
20 #ifndef BORNAGAIN_DEVICE_DATA_LLDATA_H
21 #define BORNAGAIN_DEVICE_DATA_LLDATA_H
22 
23 #include "Base/Vector/EigenCore.h"
24 #include <algorithm>
25 #include <limits>
26 #include <numeric>
27 
28 //! Template class to store data of any type in multi-dimensional space (low-level).
29 //! @ingroup tools_internal
30 
31 template <class T> class LLData {
32 public:
33  // construction, destruction and assignment
34  LLData(size_t rank, const int* dimensions);
35  LLData(const LLData<T>& right);
36  LLData<T>& operator=(const LLData<T>& right);
37  ~LLData();
38 
40 
41  // accessors
42  T& operator[](size_t i);
43  const T& operator[](size_t i) const;
44  T& atCoordinate(int* coordinate);
45  const T& atCoordinate(int* coordinate) const;
46 
47  // arithmetic operations
48  LLData<T>& operator+=(const LLData<T>& right);
49  LLData<T>& operator-=(const LLData<T>& right);
50  LLData<T>& operator*=(const LLData<T>& right);
51  LLData<T>& operator/=(const LLData<T>& right);
52 
53  // initialization, scaling
54  void setAll(const T& value);
55  void scaleAll(const T& factor);
56 
57  // retrieve basic info
58  size_t getTotalSize() const;
59  inline size_t rank() const { return m_rank; }
60  const int* dimensions() const { return m_dims; }
61  T getTotalSum() const;
62 
63 private:
64  void allocate(size_t rank, const int* dimensions);
65  void clear();
66  bool checkDimensions(size_t rank, const int* dimensions) const;
67  size_t convertCoordinate(int* coordinate) const;
68  void swapContents(LLData<T>& other);
69  T getZeroElement() const;
70 
71  size_t m_rank;
72  int* m_dims;
74 };
75 
76 #ifndef SWIG
77 template <> Eigen::Matrix2d LLData<Eigen::Matrix2d>::getZeroElement() const;
78 #endif
79 
80 // Global helper functions for arithmetic
81 template <class T> LLData<T> operator+(const LLData<T>& left, const LLData<T>& right);
82 template <class T> LLData<T> operator-(const LLData<T>& left, const LLData<T>& right);
83 template <class T> LLData<T> operator*(const LLData<T>& left, const LLData<T>& right);
84 template <class T> LLData<T> operator/(const LLData<T>& left, const LLData<T>& right);
85 
86 // Global helper functions for comparison
87 template <class T> bool HaveSameDimensions(const LLData<T>& left, const LLData<T>& right);
88 
89 template <class T>
90 inline LLData<T>::LLData(size_t rank, const int* dimensions) : m_rank(0), m_dims(0), m_data_array(0)
91 {
93 }
94 
95 template <class T> LLData<T>::LLData(const LLData<T>& right) : m_rank(0), m_dims(0), m_data_array(0)
96 {
97  allocate(right.rank(), right.dimensions());
98  for (size_t i = 0; i < getTotalSize(); ++i) {
99  m_data_array[i] = right[i];
100  }
101 }
102 
103 template <class T> LLData<T>::~LLData()
104 {
105  clear();
106 }
107 
108 template <class T> LLData<T>& LLData<T>::operator=(const LLData<T>& right)
109 {
110  if (this != &right) {
111  LLData<T> copy(right);
112  swapContents(copy);
113  }
114  return *this;
115 }
116 
117 template <class T> inline T& LLData<T>::operator[](size_t i)
118 {
119  return m_data_array[i];
120 }
121 
122 template <class T> inline const T& LLData<T>::operator[](size_t i) const
123 {
124  return m_data_array[i];
125 }
126 
127 template <class T> inline T& LLData<T>::atCoordinate(int* coordinate)
128 {
129  return m_data_array[convertCoordinate(coordinate)];
130 }
131 
132 template <class T> inline const T& LLData<T>::atCoordinate(int* coordinate) const
133 {
134  return m_data_array[convertCoordinate(coordinate)];
135 }
136 
137 template <class T> LLData<T>& LLData<T>::operator+=(const LLData<T>& right)
138 {
139  if (!HaveSameDimensions(*this, right))
140  throw std::runtime_error(
141  "Operation += on LLData requires both operands to have the same dimensions");
142  for (size_t i = 0; i < getTotalSize(); ++i) {
143  m_data_array[i] += right[i];
144  }
145  return *this;
146 }
147 
148 template <class T> LLData<T>& LLData<T>::operator-=(const LLData& right)
149 {
150  if (!HaveSameDimensions(*this, right))
151  throw std::runtime_error(
152  "Operation -= on LLData requires both operands to have the same dimensions");
153  for (size_t i = 0; i < getTotalSize(); ++i) {
154  m_data_array[i] -= right[i];
155  }
156  return *this;
157 }
158 
159 template <class T> LLData<T>& LLData<T>::operator*=(const LLData& right)
160 {
161  if (!HaveSameDimensions(*this, right))
162  throw std::runtime_error(
163  "Operation *= on LLData requires both operands to have the same dimensions");
164  for (size_t i = 0; i < getTotalSize(); ++i) {
165  m_data_array[i] *= right[i];
166  }
167  return *this;
168 }
169 
170 template <class T> LLData<T>& LLData<T>::operator/=(const LLData& right)
171 {
172  if (!HaveSameDimensions(*this, right))
173  throw std::runtime_error(
174  "Operation /= on LLData requires both operands to have the same dimensions");
175  for (size_t i = 0; i < getTotalSize(); ++i) {
176  double ratio;
177  if (std::abs(m_data_array[i] - right[i])
178  <= std::numeric_limits<double>::epsilon() * std::abs(right[i])) {
179  ratio = 1.0;
180  } else if (std::abs(right[i]) <= std::numeric_limits<double>::min()) {
181  ratio = double(m_data_array[i]) / std::numeric_limits<double>::min();
182  } else {
183  ratio = double(m_data_array[i] / right[i]);
184  }
185  m_data_array[i] = (T)ratio;
186  }
187  return *this;
188 }
189 
190 template <class T> void LLData<T>::setAll(const T& value)
191 {
192  std::fill(m_data_array, m_data_array + getTotalSize(), value);
193 }
194 
195 template <class T> void LLData<T>::scaleAll(const T& factor)
196 {
197  std::transform(m_data_array, m_data_array + getTotalSize(), m_data_array,
198  [&factor](const T& value) -> T { return value * factor; });
199 }
200 
201 template <class T> inline size_t LLData<T>::getTotalSize() const
202 {
203  int result = std::accumulate(m_dims, m_dims + m_rank, 1, std::multiplies<int>{});
204  return static_cast<size_t>(result);
205 }
206 
207 template <class T> T LLData<T>::getTotalSum() const
208 {
209  return std::accumulate(m_data_array, m_data_array + getTotalSize(), getZeroElement());
210 }
211 
212 template <class T> void LLData<T>::allocate(size_t rank, const int* dimensions)
213 {
214  clear();
215  if (!checkDimensions(rank, dimensions)) {
216  throw std::runtime_error("LLData<T>::allocate error: dimensions must be > 0");
217  }
218  m_rank = rank;
219  if (m_rank) {
220  m_dims = new int[m_rank];
221  std::copy(dimensions, dimensions + rank, m_dims);
222  m_data_array = new T[getTotalSize()];
223  } else {
224  m_data_array = new T[1];
225  }
226 }
227 
228 template <class T> void LLData<T>::clear()
229 {
230  if (m_rank > 0) {
231  m_rank = 0;
232  delete[] m_data_array;
233  delete[] m_dims;
234  m_data_array = nullptr;
235  m_dims = nullptr;
236  } else {
237  delete[] m_data_array;
238  }
239 }
240 
241 template <class T> inline bool LLData<T>::checkDimensions(size_t rank, const int* dimensions) const
242 {
243  return std::all_of(dimensions, dimensions + rank,
244  [](const int& dim) -> bool { return dim > 0; });
245 }
246 
247 template <class T> inline size_t LLData<T>::convertCoordinate(int* coordinate) const
248 {
249  size_t offset = 1;
250  size_t result = 0;
251  for (size_t i = m_rank; i > 0; --i) {
252  result += offset * coordinate[i - 1];
253  offset *= m_dims[i - 1];
254  }
255  return result;
256 }
257 
258 template <class T> void LLData<T>::swapContents(LLData<T>& other)
259 {
260  std::swap(this->m_rank, other.m_rank);
261  std::swap(this->m_dims, other.m_dims);
262  std::swap(this->m_data_array, other.m_data_array);
263 }
264 
265 template <class T> T LLData<T>::getZeroElement() const
266 {
267  T result = 0;
268  return result;
269 }
270 
271 template <class T> LLData<T> operator+(const LLData<T>& left, const LLData<T>& right)
272 {
273  LLData<T>* p_result = new LLData<T>(left);
274  (*p_result) += right;
275  return *p_result;
276 }
277 
278 template <class T> LLData<T> operator-(const LLData<T>& left, const LLData<T>& right)
279 {
280  LLData<T>* p_result = new LLData<T>(left);
281  (*p_result) -= right;
282  return *p_result;
283 }
284 
285 template <class T> LLData<T> operator*(const LLData<T>& left, const LLData<T>& right)
286 {
287  LLData<T>* p_result = new LLData<T>(left);
288  (*p_result) *= right;
289  return *p_result;
290 }
291 
292 template <class T> LLData<T> operator/(const LLData<T>& left, const LLData<T>& right)
293 {
294  LLData<T>* p_result = new LLData<T>(left);
295  *p_result /= right;
296  return *p_result;
297 }
298 
299 template <class T> bool HaveSameDimensions(const LLData<T>& left, const LLData<T>& right)
300 {
301  if (left.rank() != right.rank())
302  return false;
303  const int* ldims = left.dimensions();
304  const int* rdims = right.dimensions();
305  for (size_t i = 0; i < left.rank(); ++i) {
306  if (ldims[i] != rdims[i])
307  return false;
308  }
309  return true;
310 }
311 
312 #endif // BORNAGAIN_DEVICE_DATA_LLDATA_H
313 #endif // USER_API
Include to deal with Eigen alignment centrally.
bool HaveSameDimensions(const LLData< T > &left, const LLData< T > &right)
Definition: LLData.h:299
void swap(OutputDataIterator< TValue, TContainer > &left, OutputDataIterator< TValue, TContainer > &right)
make Swappable
BasicVector3D< T > operator+(const BasicVector3D< T > &v)
Unary plus.
auto operator*(const BasicVector3D< T > &v, const U a)
Multiplication vector by scalar.
BasicVector3D< T > operator/(const BasicVector3D< T > &v, U a)
Division vector by scalar.
BasicVector3D< T > operator-(const BasicVector3D< T > &v)
Unary minus.
Template class to store data of any type in multi-dimensional space (low-level).
Definition: LLData.h:31
size_t rank() const
Definition: LLData.h:59
size_t convertCoordinate(int *coordinate) const
Definition: LLData.h:247
LLData< T > & operator=(const LLData< T > &right)
Definition: LLData.h:108
void clear()
Definition: LLData.h:228
~LLData()
Definition: LLData.h:103
LLData< T > & operator/=(const LLData< T > &right)
Definition: LLData.h:170
LLData< T > & operator*=(const LLData< T > &right)
Definition: LLData.h:159
T getZeroElement() const
Definition: LLData.h:265
LLData< T > & operator-=(const LLData< T > &right)
Definition: LLData.h:148
T & atCoordinate(int *coordinate)
Definition: LLData.h:127
LLData< double > meanValues() const
LLData(size_t rank, const int *dimensions)
Definition: LLData.h:90
size_t m_rank
Definition: LLData.h:71
void scaleAll(const T &factor)
Definition: LLData.h:195
LLData< T > & operator+=(const LLData< T > &right)
Definition: LLData.h:137
bool checkDimensions(size_t rank, const int *dimensions) const
Definition: LLData.h:241
int * m_dims
Definition: LLData.h:72
T * m_data_array
Definition: LLData.h:73
size_t getTotalSize() const
Definition: LLData.h:201
const int * dimensions() const
Definition: LLData.h:60
void setAll(const T &value)
Definition: LLData.h:190
T & operator[](size_t i)
Definition: LLData.h:117
T getTotalSum() const
Definition: LLData.h:207
void allocate(size_t rank, const int *dimensions)
Definition: LLData.h:212
void swapContents(LLData< T > &other)
Definition: LLData.h:258