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