BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
Datafield.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/Data/Datafield.cpp
6 //! @brief Implements template specializations of class Datafield.cpp.
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 #include "Device/Data/Datafield.h"
16 #include "Base/Axis/FixedBinAxis.h"
17 #include "Base/Axis/Frame.h"
18 #include "Base/Py/PyCore.h"
19 #include "Base/Util/Assert.h"
20 #include "Base/Util/ThreadInfo.h"
21 #include <algorithm>
22 
23 
25  : m_frame(frame)
26  , m_vec(m_frame->size())
27 {
28 }
29 
30 Datafield::Datafield(Frame* frame, const std::vector<double>& vector)
31  : m_frame(frame)
32  , m_vec(vector)
33 {
34 }
35 
36 Datafield::Datafield(const std::vector<IAxis*>& axes, const std::vector<double>& vector)
37  : Datafield(new Frame(axes), vector)
38 {
39 }
40 
41 Datafield::Datafield(const std::vector<IAxis*>& axes)
42  : Datafield(new Frame(axes))
43 {
44 }
45 
47 
49 {
50  return new Datafield(m_frame->cloned_axes(), m_vec);
51 }
52 
53 void Datafield::setAt(size_t i, double val)
54 {
55  m_vec[i] = val;
56 }
57 
58 double Datafield::valAt(size_t i) const
59 {
60  return m_vec[i];
61 }
62 
63 void Datafield::setAllTo(const double& value)
64 {
65  for (double& e : m_vec)
66  e = value;
67 }
68 
69 void Datafield::setVector(const std::vector<double>& vector)
70 {
71  ASSERT(vector.size() == frame().size());
72  m_vec = vector;
73 }
74 
75 size_t Datafield::rank() const
76 {
77  return m_frame->rank();
78 }
79 
80 size_t Datafield::size() const
81 {
82  ASSERT(frame().size() == m_vec.size());
83  return frame().size();
84 }
85 
86 const Frame& Datafield::frame() const
87 {
88  return *m_frame;
89 }
90 
91 const IAxis& Datafield::axis(size_t k) const
92 {
93  return m_frame->axis(k);
94 }
95 
96 const IAxis& Datafield::xAxis() const
97 {
98  return m_frame->axis(0);
99 }
100 
101 const IAxis& Datafield::yAxis() const
102 {
103  return m_frame->axis(1);
104 }
105 
106 
107 //! Returns true if object have same dimensions
108 bool Datafield::hasSameSizes(const Datafield& other) const
109 {
110  return frame().hasSameSizes(other.frame());
111 }
112 
113 //! Returns true if object have same dimensions and shape of axis
114 bool Datafield::hasSameShape(const Datafield& other) const
115 {
116  return frame() == other.frame();
117 }
118 
119 std::vector<double> Datafield::flatVector() const
120 {
121  std::vector<double> ret(size());
122  for (size_t i = 0; i < size(); ++i)
123  ret[i] = (*this)[i];
124  return ret;
125 }
126 
128 {
129  double maxval = maxVal();
130  ASSERT(maxval > 0);
131  std::vector<double> out(frame().size());
132  for (size_t i = 0; i < frame().size(); ++i)
133  out[i] = m_vec[i] / maxval;
134  return new Datafield(m_frame->cloned_axes(), out);
135 }
136 
137 double Datafield::maxVal() const
138 {
139  return *std::max_element(m_vec.begin(), m_vec.end());
140 }
141 
142 double Datafield::minVal() const
143 {
144  return *std::min_element(m_vec.begin(), m_vec.end());
145 }
146 
147 Datafield* Datafield::crop(double xmin, double ymin, double xmax, double ymax) const
148 {
149  const std::unique_ptr<IAxis> xaxis{xAxis().clone()};
150  const std::unique_ptr<IAxis> yaxis{yAxis().clone()};
151  xaxis->clip(xmin, xmax);
152  yaxis->clip(ymin, ymax);
153 
154  std::vector<double> out(size());
155  size_t iout = 0;
156  for (size_t i = 0; i < size(); ++i) {
157  double x = m_frame->projectedCoord(i, 0);
158  double y = m_frame->projectedCoord(i, 1);
159  if (xaxis->contains(x) && yaxis->contains(y))
160  out[iout++] = m_vec[i];
161  }
162  return new Datafield(m_frame->cloned_axes(), out);
163 }
164 
165 Datafield* Datafield::crop(double xmin, double xmax) const
166 {
167  const std::unique_ptr<IAxis> xaxis{xAxis().clone()};
168  xaxis->clip(xmin, xmax);
169  std::vector<double> out(size());
170  size_t iout = 0;
171  for (size_t i = 0; i < size(); ++i) {
172  const double x = m_frame->projectedCoord(i, 0);
173  if (xaxis->contains(x))
174  out[iout++] = m_vec[i];
175  }
176  return new Datafield(m_frame->cloned_axes(), out);
177 }
178 
179 #ifdef BORNAGAIN_PYTHON
180 
182 {
183  std::vector<size_t> dimensions;
184  for (size_t i = 0; i < rank(); i++)
185  dimensions.push_back(axis(i).size());
186 
187  // for rot90 of 2-dim arrays to conform with numpy
188  if (dimensions.size() == 2)
189  std::swap(dimensions[0], dimensions[1]);
190 
191  // creating ndarray objects describing size of dimensions
192  npy_int ndim_numpy = (int)dimensions.size();
193  auto* ndimsizes_numpy = new npy_intp[dimensions.size()];
194  for (size_t i = 0; i < dimensions.size(); i++)
195  ndimsizes_numpy[i] = dimensions[i];
196 
197  // creating standalone numpy array
198  PyObject* pyarray = PyArray_SimpleNew(ndim_numpy, ndimsizes_numpy, NPY_DOUBLE);
199  delete[] ndimsizes_numpy;
200  ASSERT(pyarray);
201 
202  // getting pointer to data buffer of numpy array
203  double* array_buffer = (double*)PyArray_DATA((PyArrayObject*)pyarray);
204 
205  // filling numpy array with output_data
206  if (rank() == 2) {
207  for (size_t i = 0; i < size(); ++i) {
208  std::vector<int> axes_indices = m_frame->allIndices(i);
209  size_t offset =
210  axes_indices[0] + axis(0).size() * (axis(1).size() - 1 - axes_indices[1]);
211  array_buffer[offset] = (*this)[i];
212  }
213  } else {
214  for (size_t i = 0; i < size(); ++i)
215  *array_buffer++ = (*this)[i];
216  }
217 
218  return pyarray;
219 }
220 
221 #endif // BORNAGAIN_PYTHON
222 
223 
225 {
226  return create_xProjection(0, static_cast<int>(xAxis().size()) - 1);
227 }
228 
230 {
231  int ybin_selected = static_cast<int>(yAxis().findClosestIndex(yvalue));
232  return create_xProjection(ybin_selected, ybin_selected);
233 }
234 
235 Datafield* Datafield::xProjection(double ylow, double yup)
236 {
237  int ybinlow = static_cast<int>(yAxis().findClosestIndex(ylow));
238  int ybinup = static_cast<int>(yAxis().findClosestIndex(yup));
239  return create_xProjection(ybinlow, ybinup);
240 }
241 
243 {
244  return create_yProjection(0, static_cast<int>(xAxis().size()) - 1);
245 }
246 
248 {
249  int xbin_selected = static_cast<int>(xAxis().findClosestIndex(xvalue));
250  return create_yProjection(xbin_selected, xbin_selected);
251 }
252 
253 Datafield* Datafield::yProjection(double xlow, double xup)
254 {
255  int xbinlow = static_cast<int>(xAxis().findClosestIndex(xlow));
256  int xbinup = static_cast<int>(xAxis().findClosestIndex(xup));
257  return create_yProjection(xbinlow, xbinup);
258 }
259 
260 Datafield* Datafield::create_xProjection(int ybinlow, int ybinup)
261 {
262  std::vector<double> out(xAxis().size());
263  for (size_t i = 0; i < size(); ++i) {
264  int ybin = static_cast<int>(m_frame->projectedIndex(i, 1));
265  if (ybin >= ybinlow && ybin <= ybinup) {
266  double x = m_frame->projectedCoord(i, 0);
267  ASSERT(xAxis().contains(x));
268  size_t iout = xAxis().findClosestIndex(x);
269  out[iout] += valAt(i);
270  }
271  }
272  return new Datafield({xAxis().clone()}, out);
273 }
274 
275 Datafield* Datafield::create_yProjection(int xbinlow, int xbinup)
276 {
277  std::vector<double> out(yAxis().size());
278  for (size_t i = 0; i < size(); ++i) {
279  int xbin = static_cast<int>(m_frame->projectedIndex(i, 0));
280  if (xbin >= xbinlow && xbin <= xbinup) {
281 
282  // TODO: duplicates code from create_xProjection, move to Frame ?
283 
284  double y = m_frame->projectedCoord(i, 1);
285  ASSERT(yAxis().contains(y));
286  size_t iout = yAxis().findClosestIndex(y);
287  out[iout] += valAt(i);
288  }
289  }
290  return new Datafield({yAxis().clone()}, out);
291 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines and implements templated class Datafield.
Defines class FixedBinAxis.
Defines and implements templated class Frame.
Includes python header and takes care of warnings.
_object PyObject
Definition: PyObject.h:25
Defines struct ThreadInfo.
Stores radiation power per bin.
Definition: Datafield.h:30
std::vector< double > m_vec
Definition: Datafield.h:141
PyObject * npArray() const
Returns data as Python numpy array.
Definition: Datafield.cpp:181
const IAxis & axis(size_t k) const
Definition: Datafield.cpp:91
double maxVal() const
Definition: Datafield.cpp:137
double valAt(size_t i) const
Definition: Datafield.cpp:58
Datafield(Frame *frame)
Constructor that takes ownership of supplied frame.
Definition: Datafield.cpp:24
bool hasSameShape(const Datafield &other) const
Returns true if objects a) have same dimensions b) bin boundaries of axes coincide.
Definition: Datafield.cpp:114
Datafield * clone() const
Definition: Datafield.cpp:48
Datafield * crop(double xmin, double ymin, double xmax, double ymax) const
Definition: Datafield.cpp:147
std::unique_ptr< Frame > m_frame
Definition: Datafield.h:140
void setVector(const std::vector< double > &data_vector)
Sets new values to raw data vector.
Definition: Datafield.cpp:69
Datafield * xProjection()
Project a 2D histogram into 1D histogram along X. The projection is made from all bins along y-axis.
Definition: Datafield.cpp:224
bool hasSameSizes(const Datafield &other) const
Returns true if object have same dimensions and number of axes bins.
Definition: Datafield.cpp:108
std::vector< double > flatVector() const
Returns copy of raw data vector.
Definition: Datafield.cpp:119
size_t rank() const
Definition: Datafield.cpp:75
Datafield * normalizedToMaximum() const
Definition: Datafield.cpp:127
Datafield * create_yProjection(int xbinlow, int xbinup)
Creates projection along Y. The projections is made by collecting the data in the range between [xbin...
Definition: Datafield.cpp:275
const IAxis & yAxis() const
Definition: Datafield.cpp:101
double minVal() const
Definition: Datafield.cpp:142
Datafield * yProjection()
Project a 2D histogram into 1D histogram along Y. The projection is made from all bins along x-axis.
Definition: Datafield.cpp:242
size_t size() const
Returns total size of data buffer (product of bin number in every dimension).
Definition: Datafield.cpp:80
Datafield * create_xProjection(int ybinlow, int ybinup)
Creates projection along X. The projections is made by collecting the data in the range between [ybin...
Definition: Datafield.cpp:260
void setAllTo(const double &value)
Sets content of output data to specific value.
Definition: Datafield.cpp:63
const IAxis & xAxis() const
Definition: Datafield.cpp:96
const Frame & frame() const
Definition: Datafield.cpp:86
void setAt(size_t i, double val)
Definition: Datafield.cpp:53
Holds one or two axes.
Definition: Frame.h:27
size_t size() const
Returns total number of bins.
Definition: Frame.h:37
bool hasSameSizes(const Frame &) const
Returns true if both Frames have same rank, and all axes have same sizes.
Definition: Frame.cpp:102
Abstract base class for one-dimensional axes.
Definition: IAxis.h:27
virtual size_t findClosestIndex(double value) const =0
find bin index which is best match for given value
virtual IAxis * clone() const =0
virtual size_t size() const =0
Returns the number of bins.
virtual void clip(double lower, double upper)
Clips this axis to the given values.
Definition: IAxis.cpp:35