BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
CoordSystem1D.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/Coord/CoordSystem1D.cpp
6 //! @brief Implements CoordSystem1D class and derived classes.
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/Axis/FixedBinAxis.h"
18 #include "Base/Const/Units.h"
19 #include "Base/Math/Constants.h"
20 #include "Base/Util/Assert.h"
21 #include "Device/Coord/AxisNames.h"
22 #include "Device/Data/Datafield.h"
23 #include <cmath>
24 
25 namespace {
26 
27 double getQ(double wavelength, double angle)
28 {
29  return 4.0 * M_PI * std::sin(angle) / wavelength;
30 }
31 
32 double getInvQ(double wavelength, double q)
33 {
34  double sin_angle = q * wavelength / (4.0 * M_PI);
35  return std::asin(sin_angle);
36 }
37 
38 double backTransform(double value, Coords coords, double wavelength)
39 {
40  switch (coords) {
41  case Coords::RADIANS:
42  return value;
43  case Coords::DEGREES:
44  return Units::deg2rad(value);
45  case Coords::QSPACE:
46  return getInvQ(wavelength, value);
47  default:
48  throw std::runtime_error("CoordSystem1D/backTransform: invalid coord system");
49  }
50 }
51 
52 std::string angularAxisName(const Coords units)
53 {
54  const auto& name_map = DataUtils::AxisNames::specAxis;
55  const auto& it = name_map.find(units == Coords::UNDEFINED ? Coords::DEGREES : units);
56  ASSERT(it != name_map.cend());
57  return it->second;
58 }
59 
60 PointwiseAxis* createAxisFrom(const IAxis& axis, Coords coords, const std::string& name,
61  double wavelength)
62 {
63  std::vector<double> ret;
64  ret.reserve(axis.size());
65  for (const double value : axis.binCenters())
66  ret.emplace_back(backTransform(value, coords, wavelength));
67  return new PointwiseAxis(name, ret);
68 }
69 
70 } // namespace
71 
72 
73 // ************************************************************************************************
74 // class CoordSystem1D
75 // ************************************************************************************************
76 
78  : m_axis(axis)
79 {
80 }
81 
82 //! Returns the size of underlying axis.
83 size_t CoordSystem1D::axisSize(size_t i_axis) const
84 {
85  ASSERT(i_axis == 0);
86  return coordinateAxis()->size();
87 }
88 
89 double CoordSystem1D::calculateMin(size_t i_axis, Coords units) const
90 {
91  ASSERT(i_axis == 0);
92  units = substituteDefaultUnits(units);
93  if (units == Coords::NBINS)
94  return 0.0;
95  auto translator = getTraslatorTo(units);
96  return translator(coordinateAxis()->binCenter(0));
97 }
98 
99 double CoordSystem1D::calculateMax(size_t i_axis, Coords units) const
100 {
101  ASSERT(i_axis == 0);
102  units = substituteDefaultUnits(units);
103  const IAxis* const coordinate_axis = coordinateAxis();
104  if (units == Coords::NBINS)
105  return static_cast<double>(coordinate_axis->size());
106  auto translator = getTraslatorTo(units);
107  return translator(coordinate_axis->binCenter(coordinate_axis->size() - 1));
108 }
109 
110 IAxis* CoordSystem1D::createConvertedAxis(size_t i_axis, Coords units) const
111 {
112  ASSERT(i_axis == 0);
113  units = substituteDefaultUnits(units);
114  if (units == Coords::NBINS)
115  return new FixedBinAxis(axisName(0, units), coordinateAxis()->size(),
116  calculateMin(0, units), calculateMax(0, units));
117 
118  std::function<double(double)> translator = getTraslatorTo(units);
119  auto coords = coordinateAxis()->binCenters();
120  for (size_t i = 0, size = coords.size(); i < size; ++i)
121  coords[i] = translator(coords[i]);
122  return new PointwiseAxis(axisName(0, units), coords);
123 }
124 
126 {
127  ASSERT(data.rank() == 1);
128 
129  auto q_axis = createConvertedAxis(0, units);
130  Datafield* result = new Datafield({q_axis});
131 
132  if (units != Coords::RQ4) {
133  result->setVector(data.flatVector());
134  return result;
135  }
136 
137  for (size_t i = 0, size = result->size(); i < size; ++i)
138  (*result)[i] = data[i] * std::pow((*q_axis)[i], 4);
139  return result;
140 }
141 
142 
143 // ************************************************************************************************
144 // class AngularReflectometryCoordinates
145 // ************************************************************************************************
146 
148  const IAxis& axis,
149  Coords axis_units)
150  : CoordSystem1D(createAxisFrom(axis, axis_units, angularAxisName(axis_units), wavelength))
151  , m_wavelength(wavelength)
152 {
153  if (m_axis->min() < 0 || m_axis->max() > M_PI_2)
154  throw std::runtime_error("Error in CoordSystem1D: input axis range is out of bounds");
155 }
156 
158  const AngularReflectometryCoordinates& other)
159  : CoordSystem1D(other.m_axis->clone())
160  , m_wavelength(other.m_wavelength)
161 {
162 }
163 
165 
167 {
168  return new AngularReflectometryCoordinates(*this);
169 }
170 
172 {
174 }
175 
176 std::vector<std::map<Coords, std::string>> AngularReflectometryCoordinates::createNameMaps() const
177 {
179 }
180 
181 std::function<double(double)> AngularReflectometryCoordinates::getTraslatorTo(Coords units) const
182 {
183  switch (units) {
184  case Coords::RADIANS:
185  return [](double value) { return value; };
186  case Coords::DEGREES:
187  return [](double value) { return Units::rad2deg(value); };
188  case Coords::QSPACE:
189  return [wl = m_wavelength](double value) { return getQ(wl, value); };
190  case Coords::RQ4:
191  return [wl = m_wavelength](double value) { return getQ(wl, value); };
192  default:
193  ASSERT(0);
194  }
195 }
196 
197 
198 // ************************************************************************************************
199 // class WavenumberReflectometryCoordinates
200 // ************************************************************************************************
201 
203  : CoordSystem1D(std::move(axis))
204 {
205 }
206 
209  : CoordSystem1D(other.coordinateAxis()->clone())
210 {
211 }
212 
214 
216 {
217  return new WavenumberReflectometryCoordinates(*this);
218 }
219 
220 //! Returns the list of all available units
222 {
224 }
225 
226 //! Creates name map for axis in various units
227 std::vector<std::map<Coords, std::string>>
229 {
231 }
232 
233 //! Returns translating functional (inv. nm --> desired units)
234 std::function<double(double)> WavenumberReflectometryCoordinates::getTraslatorTo(Coords units) const
235 {
236  switch (units) {
237  case Coords::QSPACE:
238  return [](double value) { return value; };
239  case Coords::RQ4:
240  return [](double value) { return value; };
241  default:
242  ASSERT(0);
243  }
244 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines axisUnitLabel and maps in namespace AxisNames.
Defines M_PI and some more mathematical constants.
#define M_PI_2
Definition: Constants.h:45
#define M_PI
Definition: Constants.h:44
Defines CoordSystem1D class and derived classes.
Defines and implements templated class Datafield.
Defines class FixedBinAxis.
Defines class PointwiseAxis.
Defines some unit conversion factors and other constants in namespace Units.
Conversion of axis units for the case of conventional (angle-based) reflectometry.
Definition: CoordSystem1D.h:69
AngularReflectometryCoordinates * clone() const override
std::vector< Coords > availableUnits() const override
Returns the list of all available units.
AngularReflectometryCoordinates(double wavelength, const IAxis &axis, Coords axis_units=Coords::RADIANS)
Constructs the object for unit conversion.
double m_wavelength
basic wavelength in nm (for translation to q-space).
Definition: CoordSystem1D.h:94
std::function< double(double)> getTraslatorTo(Coords units) const override
Returns translating functional (rads --> desired units)
std::vector< std::map< Coords, std::string > > createNameMaps() const override
Creates name map for axis in various units.
Abstract base class to support coordinate transforms and axis labels for 1D scans....
Definition: CoordSystem1D.h:33
const IAxis * coordinateAxis() const
Definition: CoordSystem1D.h:62
double calculateMax(size_t i_axis, Coords units) const override
Calculates maximum on-axis value in given units.
virtual std::function< double(double)> getTraslatorTo(Coords units) const =0
Returns translating functional (rads --> output units)
std::unique_ptr< const IAxis > m_axis
semantics depends on subclass
Definition: CoordSystem1D.h:64
double calculateMin(size_t i_axis, Coords units) const override
Calculates minimum on-axis value in given units.
CoordSystem1D(const IAxis *&&axis)
Takes ownership of axis.
IAxis * createConvertedAxis(size_t i_axis, Coords units) const override
Creates axis in converted units.
size_t axisSize(size_t i_axis) const override
Returns the size of underlying axis.
Datafield * createConvertedData(const Datafield &data, Coords units) const override
Creates Datafield array in converter units.
Stores radiation power per bin.
Definition: Datafield.h:30
void setVector(const std::vector< double > &data_vector)
Sets new values to raw data vector.
Definition: Datafield.cpp:69
std::vector< double > flatVector() const
Returns copy of raw data vector.
Definition: Datafield.cpp:119
size_t rank() const
Definition: Datafield.cpp:75
size_t size() const
Returns total size of data buffer (product of bin number in every dimension).
Definition: Datafield.cpp:80
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
Abstract base class for one-dimensional axes.
Definition: IAxis.h:27
virtual std::vector< double > binCenters() const
Definition: IAxis.cpp:25
virtual size_t size() const =0
Returns the number of bins.
virtual double binCenter(size_t index) const =0
Coords substituteDefaultUnits(Coords units) const
std::string axisName(size_t i_axis, Coords units=Coords::UNDEFINED) const
Axis containing arbitrary (non-equidistant) coordinate values. Lower boundary of the first bin and up...
Definition: PointwiseAxis.h:33
Conversion of axis units for the case of q-defined reflectometry.
Definition: CoordSystem1D.h:99
std::vector< Coords > availableUnits() const override
Returns the list of all available units.
WavenumberReflectometryCoordinates * clone() const override
std::vector< std::map< Coords, std::string > > createNameMaps() const override
Creates name map for axis in various units.
WavenumberReflectometryCoordinates(const IAxis *&&axis)
std::function< double(double)> getTraslatorTo(Coords units) const override
Returns translating functional (inv. nm --> desired units)
Coords
Definition: Tags.h:20
BA_DEVICE_API_ const std::map< Coords, std::string > specAxisQ
Definition: AxisNames.cpp:61
BA_DEVICE_API_ const std::map< Coords, std::string > specAxis
Definition: AxisNames.cpp:55
double deg2rad(double angle)
Definition: Units.h:58
double rad2deg(double angle)
Definition: Units.h:54