BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
PointwiseAxis.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Base/Axis/PointwiseAxis.cpp
6 //! @brief Implements class PointwiseAxis.
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/Utils/PyFmt.h"
17 #include <algorithm>
18 #include <iomanip>
19 #include <stdexcept>
20 
21 const size_t min_axis_size = 2;
22 
24 {
25  return new PointwiseAxis(getName(), m_coordinates);
26 }
27 
28 Bin1D PointwiseAxis::getBin(size_t index) const
29 {
30  checkIndex(index);
31  return Bin1D(lowerBoundary(index), upperBoundary(index));
32 }
33 
34 double PointwiseAxis::getMin() const
35 {
36  return lowerBoundary(0);
37 }
38 
39 double PointwiseAxis::getMax() const
40 {
41  return upperBoundary(m_coordinates.size() - 1);
42 }
43 
44 double PointwiseAxis::getBinCenter(size_t index) const
45 {
46  checkIndex(index);
47  return m_coordinates[index];
48 }
49 
50 size_t PointwiseAxis::findClosestIndex(double value) const
51 {
52  if (value <= m_coordinates.front())
53  return 0;
54  if (value >= m_coordinates.back())
55  return m_coordinates.size() - 1;
56 
57  const auto begin = m_coordinates.begin();
58  auto result = std::lower_bound(begin, m_coordinates.end(), value);
59  size_t index = static_cast<size_t>(std::distance(begin, result));
60  return value < lowerBoundary(index) ? index - 1 : index;
61 }
62 
63 std::vector<double> PointwiseAxis::getBinBoundaries() const
64 {
65  std::vector<double> result;
66  const size_t v_size = m_coordinates.size();
67  result.reserve(v_size + 1);
68  for (size_t i = 0; i < v_size; ++i)
69  result.push_back(lowerBoundary(i));
70  result.push_back(upperBoundary(v_size - 1));
71  return result;
72 }
73 
74 PointwiseAxis* PointwiseAxis::createClippedAxis(double left, double right) const
75 {
76  if (left >= right)
77  throw std::runtime_error("Error in PointwiseAxis::createClippedAxis: "
78  "'left' should be smaller than 'right'");
79 
80  using diff_t = std::vector<double>::iterator::difference_type;
81  auto begin = m_coordinates.begin() + static_cast<diff_t>(findClosestIndex(left));
82  auto end = m_coordinates.begin() + static_cast<diff_t>(findClosestIndex(right)) + 1;
83 
84  return new PointwiseAxis(getName(), std::vector<double>(begin, end));
85 }
86 
87 std::string PointwiseAxis::pyString(const std::string& units, size_t offset) const
88 {
89  std::ostringstream result;
90  const std::string py_def_call = "numpy.asarray([";
91  const size_t total_offset = offset + py_def_call.size();
92  result << py_def_call;
93  std::vector<double> points = getBinCenters();
94  for (auto iter = points.begin(); iter != points.end() - 1; ++iter) {
95  result << pyfmt::printValue(*iter, units) << ",\n";
96  result << pyfmt::indent(total_offset);
97  }
98  result << pyfmt::printValue(points.back(), units) << "])";
99  return result.str();
100 }
101 
102 void PointwiseAxis::print(std::ostream& ostr) const
103 {
104  auto precision = std::setprecision(std::numeric_limits<double>::digits10 + 2);
105  ostr << "PointwiseAxis(\"" << getName() << "\", "
106  << ", [";
107  for (size_t i = 0, fin = m_coordinates.size() - 1; i < fin; ++i)
108  ostr << precision << m_coordinates[i] << ",";
109  ostr << precision << m_coordinates.back() << "])";
110 }
111 
112 bool PointwiseAxis::equals(const IAxis& other) const
113 {
114  if (!IAxis::equals(other))
115  return false;
116  if (const PointwiseAxis* otherAxis = dynamic_cast<const PointwiseAxis*>(&other))
117  return m_coordinates == otherAxis->getBinCenters();
118  return false;
119 }
120 
121 double PointwiseAxis::lowerBoundary(size_t index) const
122 {
123  if (index == 0)
124  return m_coordinates.front();
125  return 0.5 * (m_coordinates[index] + m_coordinates[index - 1]);
126 }
127 
128 double PointwiseAxis::upperBoundary(size_t index) const
129 {
130  if (index + 1 == m_coordinates.size())
131  return m_coordinates.back();
132  return 0.5 * (m_coordinates[index] + m_coordinates[index + 1]);
133 }
134 
135 void PointwiseAxis::checkIndex(size_t index) const
136 {
137  if (m_coordinates.size() > index)
138  return;
139  std::string message = "Error in PointwiseAxis::getBinCenter: passed index ";
140  message += std::to_string(index) + " exceeds the size ";
141  message += std::to_string(m_coordinates.size()) + " of the axis";
142  throw std::runtime_error(message);
143 }
144 
146 {
147  if (m_coordinates.size() < min_axis_size)
148  throw std::runtime_error(
149  "Error in PointwiseAxis::PointwiseAxis: the size of passed coordinate array is "
150  "less than minimum acceptable value");
151 
152  const auto begin = m_coordinates.begin();
153  const auto end = m_coordinates.end();
154 
155  if (!std::is_sorted(begin, end))
156  throw std::runtime_error("Error in PointwiseAxis::PointwiseAxis: passed coordinates are "
157  "not sorted in ascending order");
158 
159  if (std::adjacent_find(begin, end) != end)
160  throw std::runtime_error("Error in PointwiseAxis::PointwiseAxis: passed coordinate vector "
161  "contains repeating values");
162 }
const size_t min_axis_size
Defines class PointwiseAxis.
Defines functions in namespace pyfmt.
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 containing arbitrary (non-equidistant) coordinate values.
Definition: PointwiseAxis.h:33
double upperBoundary(size_t index) const
double lowerBoundary(size_t index) const
PointwiseAxis(String &&name, Vector &&coordinate_values)
Definition: PointwiseAxis.h:36
Bin1D getBin(size_t index) const override
retrieve a 1d bin for the given index
PointwiseAxis * clone() const override
clone function
std::vector< double > getBinCenters() const override
Definition: PointwiseAxis.h:69
void checkIndex(size_t index) const
double getBinCenter(size_t index) const override
Returns the coordinate corresponding to the given index.
std::vector< double > m_coordinates
Definition: PointwiseAxis.h:87
PointwiseAxis * createClippedAxis(double left, double right) const override
Creates a new clipped axis.
std::string pyString(const std::string &units, size_t offset) const final
std::vector< double > getBinBoundaries() const override
double getMax() const override
Returns value of last on-axis point.
size_t findClosestIndex(double value) const override
find index of the coordinate closest to the given value
double getMin() const override
Returns value of first on-axis point.
bool equals(const IAxis &other) const override
void print(std::ostream &ostr) const override
void sanityCheck() const
std::string indent(size_t width)
Returns a string of blanks with given width.
Definition: PyFmt.cpp:141
std::string printValue(double value, const std::string &units)
Definition: PyFmt.cpp:104
Definition: Bin.h:20