BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
UnitConverter1D.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Core/Scan/UnitConverter1D.cpp
6 //! @brief Implements UnitConverter1D 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 
18 #include "Base/Const/Units.h"
19 #include "Device/Beam/Beam.h"
20 #include "Device/Data/OutputData.h"
22 #include "Core/Scan/QSpecScan.h"
23 #include "Device/Unit/AxisNames.h"
24 
25 namespace
26 {
27 double getQ(double wavelength, double angle);
28 
29 double getInvQ(double wavelength, double q);
30 
31 std::unique_ptr<PointwiseAxis>
32 createTranslatedAxis(const IAxis& axis, std::function<double(double)> translator, std::string name);
33 } // namespace
34 
35 std::unique_ptr<UnitConverter1D> UnitConverter1D::createUnitConverter(const ISpecularScan& scan)
36 {
37  if (const auto* aScan = dynamic_cast<const AngularSpecScan*>(&scan))
38  return std::make_unique<UnitConverterConvSpec>(*aScan);
39 
40  if (const auto* qScan = dynamic_cast<const QSpecScan*>(&scan))
41  return std::make_unique<UnitConverterQSpec>(*qScan);
42 
43  throw std::runtime_error("Bug in UnitConverter1D::createUnitConverter: invalid case");
44 }
45 
47 {
48  return 1u;
49 }
50 
51 double UnitConverter1D::calculateMin(size_t i_axis, Axes::Units units_type) const
52 {
53  checkIndex(i_axis);
54  units_type = substituteDefaultUnits(units_type);
55  if (units_type == Axes::Units::NBINS)
56  return 0.0;
57  auto translator = getTraslatorTo(units_type);
58  return translator(coordinateAxis()->getBinCenter(0));
59 }
60 
61 double UnitConverter1D::calculateMax(size_t i_axis, Axes::Units units_type) const
62 {
63  checkIndex(i_axis);
64  units_type = substituteDefaultUnits(units_type);
65  auto coordinate_axis = coordinateAxis();
66  if (units_type == Axes::Units::NBINS)
67  return static_cast<double>(coordinate_axis->size());
68  auto translator = getTraslatorTo(units_type);
69  return translator(coordinate_axis->getBinCenter(coordinate_axis->size() - 1));
70 }
71 
72 std::unique_ptr<IAxis> UnitConverter1D::createConvertedAxis(size_t i_axis, Axes::Units units) const
73 {
74  checkIndex(i_axis);
75  units = substituteDefaultUnits(units);
76  if (units == Axes::Units::NBINS)
77  return std::make_unique<FixedBinAxis>(axisName(0, units), coordinateAxis()->size(),
78  calculateMin(0, units), calculateMax(0, units));
79  return createTranslatedAxis(*coordinateAxis(), getTraslatorTo(units), axisName(0, units));
80 }
81 
82 std::unique_ptr<OutputData<double>>
84 {
85  if (data.getRank() != 1)
86  throw std::runtime_error("Error in UnitConverter1D::createConvertedData: unexpected "
87  "dimensions of the input data");
88 
89  std::unique_ptr<OutputData<double>> result(new OutputData<double>);
90  auto q_axis = createConvertedAxis(0, units);
91  result->addAxis(*q_axis);
92 
93  if (units != Axes::Units::RQ4) {
94  result->setRawDataVector(data.getRawDataVector());
95  return result;
96  }
97 
98  for (size_t i = 0, size = result->getAllocatedSize(); i < size; ++i)
99  (*result)[i] = data[i] * std::pow((*q_axis)[i], 4);
100  return result;
101 }
102 
104  Axes::Units axis_units)
105  : m_wavelength(beam.getWavelength())
106 {
107  m_axis = createTranslatedAxis(axis, getTraslatorFrom(axis_units), axisName(0, axis_units));
108  if (m_axis->getMin() < 0 || m_axis->getMax() > M_PI_2)
109  throw std::runtime_error("Error in UnitConverter1D: input axis range is out of bounds");
110 }
111 
113  : m_wavelength(handler.wavelength()), m_axis(handler.coordinateAxis()->clone())
114 {
115 }
116 
118 
120 {
121  return new UnitConverterConvSpec(*this);
122 }
123 
124 size_t UnitConverterConvSpec::axisSize(size_t i_axis) const
125 {
126  checkIndex(i_axis);
127  return m_axis->size();
128 }
129 
130 std::vector<Axes::Units> UnitConverterConvSpec::availableUnits() const
131 {
132  return {Axes::Units::NBINS, Axes::Units::RADIANS, Axes::Units::DEGREES, Axes::Units::QSPACE,
133  Axes::Units::RQ4};
134 }
135 
137 {
138  return Axes::Units::DEGREES;
139 }
140 
142  : m_wavelength(other.m_wavelength), m_axis(other.m_axis->clone())
143 {
144 }
145 
146 std::vector<std::map<Axes::Units, std::string>> UnitConverterConvSpec::createNameMaps() const
147 {
148  std::vector<std::map<Axes::Units, std::string>> result;
149  result.push_back(AxisNames::InitSpecAxis());
150  return result;
151 }
152 
153 std::function<double(double)> UnitConverterConvSpec::getTraslatorFrom(Axes::Units units_type) const
154 {
155  switch (units_type) {
156  case Axes::Units::RADIANS:
157  return [](double value) { return value; };
158  case Axes::Units::DEGREES:
159  return [](double value) { return Units::deg2rad(value); };
160  case Axes::Units::QSPACE:
161  return [this](double value) { return getInvQ(m_wavelength, value); };
162  default:
163  throwUnitsError("UnitConverterConvSpec::getTraslatorFrom",
164  {Axes::Units::RADIANS, Axes::Units::DEGREES, Axes::Units::QSPACE});
165  }
166 }
167 
168 std::function<double(double)> UnitConverterConvSpec::getTraslatorTo(Axes::Units units_type) const
169 {
170  switch (units_type) {
171  case Axes::Units::RADIANS:
172  return [](double value) { return value; };
173  case Axes::Units::DEGREES:
174  return [](double value) { return Units::rad2deg(value); };
175  case Axes::Units::QSPACE:
176  return [wl = m_wavelength](double value) { return getQ(wl, value); };
177  case Axes::Units::RQ4:
178  return [wl = m_wavelength](double value) { return getQ(wl, value); };
179  default:
180  throwUnitsError("UnitConverterConvSpec::getTraslatorTo", availableUnits());
181  }
182 }
183 
185  : m_axis(handler.coordinateAxis()->clone())
186 {
187 }
188 
190 
192 {
193  return new UnitConverterQSpec(*this);
194 }
195 
196 //! Returns the size of underlying axis.
197 size_t UnitConverterQSpec::axisSize(size_t i_axis) const
198 {
199  checkIndex(i_axis);
200  return m_axis->size();
201 }
202 
203 //! Returns the list of all available units
204 std::vector<Axes::Units> UnitConverterQSpec::availableUnits() const
205 {
206  return {Axes::Units::NBINS, Axes::Units::QSPACE, Axes::Units::RQ4};
207 }
208 
209 //! Returns default units to convert to.
211 {
212  return Axes::Units::QSPACE;
213 }
214 
216  : m_axis(std::unique_ptr<IAxis>(other.coordinateAxis()->clone()))
217 {
218 }
219 
220 //! Creates name map for axis in various units
221 std::vector<std::map<Axes::Units, std::string>> UnitConverterQSpec::createNameMaps() const
222 {
223  std::vector<std::map<Axes::Units, std::string>> result;
224  result.push_back(AxisNames::InitSpecAxisQ());
225  return result;
226 }
227 
228 //! Returns translating functional (inv. nm --> desired units)
229 std::function<double(double)> UnitConverterQSpec::getTraslatorTo(Axes::Units units_type) const
230 {
231  switch (units_type) {
232  case Axes::Units::QSPACE:
233  return [](double value) { return value; };
234  case Axes::Units::RQ4:
235  return [](double value) { return value; };
236  default:
237  throwUnitsError("UnitConverterQSpec::getTraslatorTo", availableUnits());
238  }
239 }
240 
241 namespace
242 {
243 double getQ(double wavelength, double angle)
244 {
245  return 4.0 * M_PI * std::sin(angle) / wavelength;
246 }
247 
248 double getInvQ(double wavelength, double q)
249 {
250  double sin_angle = q * wavelength / (4.0 * M_PI);
251  return std::asin(sin_angle);
252 }
253 
254 std::unique_ptr<PointwiseAxis>
255 createTranslatedAxis(const IAxis& axis, std::function<double(double)> translator, std::string name)
256 {
257  auto coordinates = axis.getBinCenters();
258  for (size_t i = 0, size = coordinates.size(); i < size; ++i)
259  coordinates[i] = translator(coordinates[i]);
260  return std::make_unique<PointwiseAxis>(name, coordinates);
261 }
262 } // namespace
Declares AngularSpecScan class.
Defines namespace AxisNames.
Defines class Beam.
Defines M_PI and some more mathematical constants.
#define M_PI_2
Definition: MathConstants.h:40
#define M_PI
Definition: MathConstants.h:39
Defines and implements template class OutputData.
Defines class PointwiseAxis.
Declares QSpecScan class.
Defines UnitConverter1D class and derived classes.
Defines some unit conversion factors and other constants in namespace Units.
Scan type with inclination angles as coordinate values and a unique wavelength.
Beam defined by wavelength, direction and intensity.
Definition: Beam.h:27
Interface for one-dimensional axes.
Definition: IAxis.h:25
virtual std::vector< double > getBinCenters() const
Definition: IAxis.cpp:23
Pure virtual base class for all types of specular scans.
Definition: ISpecularScan.h:31
Axes::Units substituteDefaultUnits(Axes::Units units) const
void checkIndex(size_t i_axis) const
void throwUnitsError(std::string method, std::vector< Axes::Units > available) const
std::string axisName(size_t i_axis, Axes::Units units_type=Axes::Units::DEFAULT) const
std::vector< T > getRawDataVector() const
Returns copy of raw data vector.
Definition: OutputData.h:335
size_t getRank() const
Returns number of dimensions.
Definition: OutputData.h:59
Scan type with z-components of scattering vector as coordinate values.
Definition: QSpecScan.h:29
static std::unique_ptr< UnitConverter1D > createUnitConverter(const ISpecularScan &handler)
Factory function to create unit converter for particular type of specular data.
size_t dimension() const override
Returns dimensionality of converted canvas.
std::unique_ptr< OutputData< double > > createConvertedData(const OutputData< double > &data, Axes::Units units) const override
Creates OutputData array in converter units.
std::unique_ptr< IAxis > createConvertedAxis(size_t i_axis, Axes::Units units) const override
Creates axis in converted units.
double calculateMax(size_t i_axis, Axes::Units units_type) const override
Calculates maximum on-axis value in given units.
virtual const IAxis * coordinateAxis() const =0
double calculateMin(size_t i_axis, Axes::Units units_type) const override
Calculates minimum on-axis value in given units.
virtual std::function< double(double)> getTraslatorTo(Axes::Units units_type) const =0
Returns translating functional (rads --> output units)
Conversion of axis units for the case of conventional (angle-based) reflectometry.
UnitConverterConvSpec(const Beam &beam, const IAxis &axis, Axes::Units axis_units=Axes::Units::RADIANS)
Constructs the object for unit conversion.
size_t axisSize(size_t i_axis) const override
Returns the size of underlying axis.
double m_wavelength
basic wavelength in nm (for translation to q-space).
std::vector< std::map< Axes::Units, std::string > > createNameMaps() const override
Creates name map for axis in various units.
UnitConverterConvSpec * clone() const override
~UnitConverterConvSpec() override
std::function< double(double)> getTraslatorTo(Axes::Units units_type) const override
Returns translating functional (rads --> desired units)
std::function< double(double)> getTraslatorFrom(Axes::Units units_type) const
Returns translating functional (input units --> rads)
Axes::Units defaultUnits() const override
Returns default units to convert to.
std::unique_ptr< IAxis > m_axis
basic inclination angles (in rads).
std::vector< Axes::Units > availableUnits() const override
Returns the list of all available units.
Conversion of axis units for the case of q-defined reflectometry.
UnitConverterQSpec(const QSpecScan &handler)
std::function< double(double)> getTraslatorTo(Axes::Units units_type) const override
Returns translating functional (inv. nm --> desired units)
~UnitConverterQSpec() override
std::unique_ptr< IAxis > m_axis
qz values (in inv. nm).
std::vector< std::map< Axes::Units, std::string > > createNameMaps() const override
Creates name map for axis in various units.
UnitConverterQSpec * clone() const override
Axes::Units defaultUnits() const override
Returns default units to convert to.
size_t axisSize(size_t i_axis) const override
Returns the size of underlying axis.
std::vector< Axes::Units > availableUnits() const override
Returns the list of all available units.
std::map< Axes::Units, std::string > InitSpecAxisQ()
Definition: AxisNames.cpp:94
std::map< Axes::Units, std::string > InitSpecAxis()
Definition: AxisNames.cpp:83
double deg2rad(double angle)
Definition: Units.h:47
double rad2deg(double angle)
Definition: Units.h:43
double getQ(double wavelength, double angle)
double getInvQ(double wavelength, double q)
std::unique_ptr< PointwiseAxis > createTranslatedAxis(const IAxis &axis, std::function< double(double)> translator, std::string name)