BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
VariableBinAxis.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Base/Axis/VariableBinAxis.cpp
6 //! @brief Implements VariableBinAxis class.
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 
16 #include "Base/Types/Exceptions.h"
17 #include "Base/Utils/Algorithms.h"
18 #include <algorithm>
19 #include <iomanip>
20 
21 VariableBinAxis::VariableBinAxis(const std::string& name, size_t nbins,
22  const std::vector<double>& bin_boundaries)
23  : IAxis(name), m_nbins(nbins)
24 {
25  if (m_nbins != bin_boundaries.size() - 1)
27  "VariableBinAxis::VariableBinAxis() -> Error! "
28  "The size of bin_boundaries should be of size [nbins+1].");
29 
30  setBinBoundaries(bin_boundaries);
31 }
32 
33 VariableBinAxis::VariableBinAxis(const std::string& name, size_t nbins)
34  : IAxis(name), m_nbins(nbins)
35 {
36 }
37 
39 {
41  return result;
42 }
43 
44 double VariableBinAxis::operator[](size_t index) const
45 {
46  return getBin(index).getMidPoint();
47 }
48 
49 Bin1D VariableBinAxis::getBin(size_t index) const
50 {
51  if (index >= m_nbins)
52  throw Exceptions::OutOfBoundsException("VariableBinAxis::getBin() -> Error. Wrong index.");
53 
54  Bin1D result(m_bin_boundaries[index], m_bin_boundaries[index + 1]);
55  return result;
56 }
57 
59 {
60  return m_bin_boundaries.front();
61 }
62 
64 {
65  return m_bin_boundaries.back();
66 }
67 
68 double VariableBinAxis::getBinCenter(size_t index) const
69 {
70  return getBin(index).getMidPoint();
71 }
72 
73 size_t VariableBinAxis::findClosestIndex(double value) const
74 {
75  if (m_bin_boundaries.size() < 2)
77  "VariableBinAxis::findClosestIndex() -> Error! "
78  "VariableBinAxis not correctly initialized");
79  if (value < getMin()) {
80  return 0;
81  } else if (value >= getMax()) {
82  return m_nbins - 1;
83  }
84 
85  std::vector<double>::const_iterator top_limit =
86  std::lower_bound(m_bin_boundaries.begin(), m_bin_boundaries.end(), value);
87  if (*top_limit != value)
88  --top_limit;
89  size_t nbin = top_limit - m_bin_boundaries.begin();
90  return nbin;
91 }
92 
93 std::vector<double> VariableBinAxis::getBinCenters() const
94 {
95  std::vector<double> result;
96  result.resize(size(), 0.0);
97  for (size_t i = 0; i < size(); ++i) {
98  result[i] = getBin(i).getMidPoint();
99  }
100  return result;
101 }
102 
103 VariableBinAxis* VariableBinAxis::createClippedAxis(double left, double right) const
104 {
105 
106  if (left >= right)
107  throw Exceptions::LogicErrorException("VariableBinAxis::createClippedAxis() -> Error. "
108  "'left'' should be smaller than 'right'");
109 
110  if (left < getMin())
111  left = getBin(0).getMidPoint();
112  if (right >= getMax())
113  right = getBin(size() - 1).getMidPoint();
114 
115  size_t nbin1 = findClosestIndex(left);
116  size_t nbin2 = findClosestIndex(right);
117 
118  size_t new_nbins = nbin2 - nbin1 + 1;
119  std::vector<double> new_boundaries;
120  for (size_t i = 0; i < new_nbins + 1; ++i) {
121  new_boundaries.push_back(m_bin_boundaries[nbin1 + i]);
122  }
123 
124  return new VariableBinAxis(getName(), new_nbins, new_boundaries);
125 }
126 
127 std::string VariableBinAxis::pyString(const std::string&, size_t) const
128 {
129  throw std::runtime_error("VariableBinAxis::pyString not yet implemented"); // TODO
130 }
131 
132 void VariableBinAxis::print(std::ostream& ostr) const
133 {
134  ostr << "VariableBinAxis(\"" << getName() << "\", " << size() << ", [";
135  for (size_t i = 0; i < m_bin_boundaries.size(); ++i) {
136  ostr << std::setprecision(std::numeric_limits<double>::digits10 + 2) << m_bin_boundaries[i];
137  if (i != m_bin_boundaries.size() - 1)
138  ostr << ", ";
139  }
140  ostr << "])";
141 }
142 
143 bool VariableBinAxis::equals(const IAxis& other) const
144 {
145  if (!IAxis::equals(other))
146  return false;
147  if (const VariableBinAxis* p_other_cast = dynamic_cast<const VariableBinAxis*>(&other)) {
148  if (size() != p_other_cast->size())
149  return false;
150  for (size_t i = 0; i < m_bin_boundaries.size(); ++i) {
151  if (!algo::almostEqual(m_bin_boundaries[i], p_other_cast->m_bin_boundaries[i])) {
152  return false;
153  }
154  }
155  return true;
156  }
157  return false;
158 }
159 
160 void VariableBinAxis::setBinBoundaries(const std::vector<double>& bin_boundaries)
161 {
162  // checking that values are sorted
163  std::vector<double> vec_sorted = bin_boundaries;
164  std::sort(vec_sorted.begin(), vec_sorted.end());
165  for (size_t i = 0; i < bin_boundaries.size(); ++i) {
166  if (vec_sorted[i] != bin_boundaries[i])
167  throw Exceptions::LogicErrorException("VariableBinAxis::VariableBinAxis() -> Error. "
168  "Array with bin edges is not sorted.");
169  }
170 
171  std::vector<double> vec = bin_boundaries;
172  vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
173 
174  if (vec.size() != bin_boundaries.size())
175  throw Exceptions::LogicErrorException("VariableBinAxis::VariableBinAxis() -> Error. "
176  "Array with bin edges contains repeating values.");
177 
178  m_bin_boundaries = bin_boundaries;
179 }
Defines and implements namespace algo with some algorithms.
Defines many exception classes in namespace Exceptionss.
Defines class VariableBinAxis.
Interface for one-dimensional axes.
Definition: IAxis.h:25
virtual bool equals(const IAxis &other) const
Definition: IAxis.cpp:18
std::string getName() const
retrieve the label of the axis
Definition: IAxis.h:40
Axis with variable bin size.
double getMax() const
Returns value of last point of axis.
double getBinCenter(size_t index) const
size_t size() const
retrieve the number of bins
void setBinBoundaries(const std::vector< double > &bin_boundaries)
double operator[](size_t index) const
indexed accessor retrieves a sample
std::vector< double > getBinCenters() const
virtual bool equals(const IAxis &other) const
Bin1D getBin(size_t index) const
retrieve a 1d bin for the given index
double getMin() const
Returns value of first point of axis.
VariableBinAxis(const std::string &name, size_t nbins, const std::vector< double > &bin_boundaries)
VariableBinAxis constructor.
std::vector< double > m_bin_boundaries
vector containing the bin limits
virtual VariableBinAxis * createClippedAxis(double left, double right) const
Creates a new clipped axis.
size_t findClosestIndex(double value) const
find bin index which is best match for given value
virtual void print(std::ostream &ostr) const
std::string pyString(const std::string &units, size_t offset) const final
VariableBinAxis * clone() const
clone function
bool almostEqual(double a, double b)
Returns true if two doubles agree within machine epsilon.
Definition: Algorithms.h:30
Definition: Bin.h:20
double getMidPoint() const
Definition: Bin.h:25