BornAgain  1.19.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 reflection and scattering
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 
17 #include "Base/Const/Units.h"
18 #include "Base/Math/Constants.h"
20 #include "Core/Scan/QSpecScan.h"
21 #include "Device/Beam/Beam.h"
22 #include "Device/Data/OutputData.h"
23 #include "Device/Unit/AxisNames.h"
24 
25 namespace {
26 double getQ(double wavelength, double angle);
27 
28 double getInvQ(double wavelength, double q);
29 
30 std::unique_ptr<PointwiseAxis>
31 createTranslatedAxis(const IAxis& axis, std::function<double(double)> translator, std::string name);
32 } // namespace
33 
34 std::unique_ptr<UnitConverter1D> UnitConverter1D::createUnitConverter(const ISpecularScan& scan)
35 {
36  if (const auto* aScan = dynamic_cast<const AngularSpecScan*>(&scan))
37  return std::make_unique<UnitConverterConvSpec>(*aScan);
38 
39  if (const auto* qScan = dynamic_cast<const QSpecScan*>(&scan))
40  return std::make_unique<UnitConverterQSpec>(*qScan);
41 
42  throw std::runtime_error("Bug in UnitConverter1D::createUnitConverter: invalid case");
43 }
44 
46 {
47  return 1u;
48 }
49 
50 double UnitConverter1D::calculateMin(size_t i_axis, Axes::Units units_type) const
51 {
52  checkIndex(i_axis);
53  units_type = substituteDefaultUnits(units_type);
54  if (units_type == Axes::Units::NBINS)
55  return 0.0;
56  auto translator = getTraslatorTo(units_type);
57  return translator(coordinateAxis()->binCenter(0));
58 }
59 
60 double UnitConverter1D::calculateMax(size_t i_axis, Axes::Units units_type) const
61 {
62  checkIndex(i_axis);
63  units_type = substituteDefaultUnits(units_type);
64  auto coordinate_axis = coordinateAxis();
65  if (units_type == Axes::Units::NBINS)
66  return static_cast<double>(coordinate_axis->size());
67  auto translator = getTraslatorTo(units_type);
68  return translator(coordinate_axis->binCenter(coordinate_axis->size() - 1));
69 }
70 
71 std::unique_ptr<IAxis> UnitConverter1D::createConvertedAxis(size_t i_axis, Axes::Units units) const
72 {
73  checkIndex(i_axis);
74  units = substituteDefaultUnits(units);
75  if (units == Axes::Units::NBINS)
76  return std::make_unique<FixedBinAxis>(axisName(0, units), coordinateAxis()->size(),
77  calculateMin(0, units), calculateMax(0, units));
78  return createTranslatedAxis(*coordinateAxis(), getTraslatorTo(units), axisName(0, units));
79 }
80 
81 std::unique_ptr<OutputData<double>>
83 {
84  if (data.rank() != 1)
85  throw std::runtime_error("Error in UnitConverter1D::createConvertedData: unexpected "
86  "dimensions of the input data");
87 
88  std::unique_ptr<OutputData<double>> result(new OutputData<double>);
89  auto q_axis = createConvertedAxis(0, units);
90  result->addAxis(*q_axis);
91 
92  if (units != Axes::Units::RQ4) {
93  result->setRawDataVector(data.getRawDataVector());
94  return result;
95  }
96 
97  for (size_t i = 0, size = result->getAllocatedSize(); i < size; ++i)
98  (*result)[i] = data[i] * std::pow((*q_axis)[i], 4);
99  return result;
100 }
101 
103  Axes::Units axis_units)
104  : m_wavelength(beam.wavelength())
105 {
106  m_axis = createTranslatedAxis(axis, getTraslatorFrom(axis_units), axisName(0, axis_units));
107  if (m_axis->lowerBound() < 0 || m_axis->upperBound() > M_PI_2)
108  throw std::runtime_error("Error in UnitConverter1D: input axis range is out of bounds");
109 }
110 
112  : m_wavelength(handler.wavelength()), m_axis(handler.coordinateAxis()->clone())
113 {
114 }
115 
117 
119 {
120  return new UnitConverterConvSpec(*this);
121 }
122 
123 size_t UnitConverterConvSpec::axisSize(size_t i_axis) const
124 {
125  checkIndex(i_axis);
126  return m_axis->size();
127 }
128 
129 std::vector<Axes::Units> UnitConverterConvSpec::availableUnits() const
130 {
131  return {Axes::Units::NBINS, Axes::Units::RADIANS, Axes::Units::DEGREES, Axes::Units::QSPACE,
132  Axes::Units::RQ4};
133 }
134 
136 {
137  return Axes::Units::DEGREES;
138 }
139 
141  : m_wavelength(other.m_wavelength), m_axis(other.m_axis->clone())
142 {
143 }
144 
145 std::vector<std::map<Axes::Units, std::string>> UnitConverterConvSpec::createNameMaps() const
146 {
147  std::vector<std::map<Axes::Units, std::string>> result;
148  result.push_back(AxisNames::InitSpecAxis());
149  return result;
150 }
151 
152 std::function<double(double)> UnitConverterConvSpec::getTraslatorFrom(Axes::Units units_type) const
153 {
154  switch (units_type) {
155  case Axes::Units::RADIANS:
156  return [](double value) { return value; };
157  case Axes::Units::DEGREES:
158  return [](double value) { return Units::deg2rad(value); };
159  case Axes::Units::QSPACE:
160  return [this](double value) { return getInvQ(m_wavelength, value); };
161  default:
162  throwUnitsError("UnitConverterConvSpec::getTraslatorFrom",
163  {Axes::Units::RADIANS, Axes::Units::DEGREES, Axes::Units::QSPACE});
164  }
165 }
166 
167 std::function<double(double)> UnitConverterConvSpec::getTraslatorTo(Axes::Units units_type) const
168 {
169  switch (units_type) {
170  case Axes::Units::RADIANS:
171  return [](double value) { return value; };
172  case Axes::Units::DEGREES:
173  return [](double value) { return Units::rad2deg(value); };
174  case Axes::Units::QSPACE:
175  return [wl = m_wavelength](double value) { return getQ(wl, value); };
176  case Axes::Units::RQ4:
177  return [wl = m_wavelength](double value) { return getQ(wl, value); };
178  default:
179  throwUnitsError("UnitConverterConvSpec::getTraslatorTo", availableUnits());
180  }
181 }
182 
184  : m_axis(handler.coordinateAxis()->clone())
185 {
186 }
187 
189 
191 {
192  return new UnitConverterQSpec(*this);
193 }
194 
195 //! Returns the size of underlying axis.
196 size_t UnitConverterQSpec::axisSize(size_t i_axis) const
197 {
198  checkIndex(i_axis);
199  return m_axis->size();
200 }
201 
202 //! Returns the list of all available units
203 std::vector<Axes::Units> UnitConverterQSpec::availableUnits() const
204 {
205  return {Axes::Units::NBINS, Axes::Units::QSPACE, Axes::Units::RQ4};
206 }
207 
208 //! Returns default units to convert to.
210 {
211  return Axes::Units::QSPACE;
212 }
213 
215  : m_axis(std::unique_ptr<IAxis>(other.coordinateAxis()->clone()))
216 {
217 }
218 
219 //! Creates name map for axis in various units
220 std::vector<std::map<Axes::Units, std::string>> UnitConverterQSpec::createNameMaps() const
221 {
222  std::vector<std::map<Axes::Units, std::string>> result;
223  result.push_back(AxisNames::InitSpecAxisQ());
224  return result;
225 }
226 
227 //! Returns translating functional (inv. nm --> desired units)
228 std::function<double(double)> UnitConverterQSpec::getTraslatorTo(Axes::Units units_type) const
229 {
230  switch (units_type) {
231  case Axes::Units::QSPACE:
232  return [](double value) { return value; };
233  case Axes::Units::RQ4:
234  return [](double value) { return value; };
235  default:
236  throwUnitsError("UnitConverterQSpec::getTraslatorTo", availableUnits());
237  }
238 }
239 
240 namespace {
241 double getQ(double wavelength, double angle)
242 {
243  return 4.0 * M_PI * std::sin(angle) / wavelength;
244 }
245 
246 double getInvQ(double wavelength, double q)
247 {
248  double sin_angle = q * wavelength / (4.0 * M_PI);
249  return std::asin(sin_angle);
250 }
251 
252 std::unique_ptr<PointwiseAxis>
253 createTranslatedAxis(const IAxis& axis, std::function<double(double)> translator, std::string name)
254 {
255  auto coordinates = axis.binCenters();
256  for (size_t i = 0, size = coordinates.size(); i < size; ++i)
257  coordinates[i] = translator(coordinates[i]);
258  return std::make_unique<PointwiseAxis>(name, coordinates);
259 }
260 } // namespace
Declares AngularSpecScan class.
Defines namespace AxisNames.
Defines class Beam.
Defines M_PI and some more mathematical constants.
#define M_PI_2
Definition: Constants.h:45
#define M_PI
Definition: Constants.h:44
Defines and implements templated 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.
An incident neutron or x-ray beam.
Definition: Beam.h:27
Interface for one-dimensional axes.
Definition: IAxis.h:25
virtual std::vector< double > binCenters() const
Definition: IAxis.cpp:22
Abstract base class for all types of specular scans.
Definition: ISpecularScan.h:32
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
size_t rank() const
Returns number of dimensions.
Definition: OutputData.h:56
std::vector< T > getRawDataVector() const
Returns copy of raw data vector.
Definition: OutputData.h:334
Scan type with z-components of scattering vector as coordinate values.
Definition: QSpecScan.h:28
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:93
std::map< Axes::Units, std::string > InitSpecAxis()
Definition: AxisNames.cpp:82
QString const & name(EShape k)
Definition: particles.cpp:21
double deg2rad(double angle)
Definition: Units.h:59
double rad2deg(double angle)
Definition: Units.h:55
Definition: filesystem.h:81