30 double getQ(
double wavelength,
double angle)
32 return 4.0 * M_PI * std::sin(angle) / wavelength;
36 UnitConverterSimple::UnitConverterSimple(
const Beam& beam)
37 : m_wavelength(beam.getWavelength()), m_alpha_i(-beam.getAlpha()), m_phi_i(beam.getPhi())
41 size_t UnitConverterSimple::dimension()
const
43 return m_axis_data_table.size();
46 void UnitConverterSimple::addAxisData(std::string name,
double min,
double max,
47 Axes::Units default_units,
size_t nbins)
49 AxisData axis_data{name, min, max, default_units, nbins};
50 m_axis_data_table.push_back(axis_data);
53 double UnitConverterSimple::calculateMin(
size_t i_axis, Axes::Units units_type)
const
56 units_type = substituteDefaultUnits(units_type);
57 const auto& axis_data = m_axis_data_table[i_axis];
58 if (units_type == Axes::Units::NBINS) {
61 return calculateValue(i_axis, units_type, axis_data.min);
64 double UnitConverterSimple::calculateMax(
size_t i_axis, Axes::Units units_type)
const
67 units_type = substituteDefaultUnits(units_type);
68 const auto& axis_data = m_axis_data_table[i_axis];
69 if (units_type == Axes::Units::NBINS) {
70 return static_cast<double>(axis_data.nbins);
72 return calculateValue(i_axis, units_type, axis_data.max);
75 size_t UnitConverterSimple::axisSize(
size_t i_axis)
const
78 return m_axis_data_table[i_axis].nbins;
83 return {Axes::Units::NBINS, Axes::Units::RADIANS, Axes::Units::DEGREES};
86 std::unique_ptr<IAxis> UnitConverterSimple::createConvertedAxis(
size_t i_axis,
87 Axes::Units units)
const
89 const double min = calculateMin(i_axis, units);
90 const double max = calculateMax(i_axis, units);
91 const auto& axis_name = axisName(i_axis, units);
92 const auto axis_size = axisSize(i_axis);
93 return std::make_unique<FixedBinAxis>(axis_name, axis_size, min, max);
97 : m_axis_data_table(other.m_axis_data_table), m_wavelength(other.m_wavelength),
98 m_alpha_i(other.m_alpha_i), m_phi_i(other.m_phi_i)
102 void UnitConverterSimple::addDetectorAxis(
const IDetector& detector,
size_t i_axis)
104 const auto& axis = detector.getAxis(i_axis);
106 const auto& axis_name = axisName(i_axis);
108 auto P_roi_axis = p_roi->clipAxisToRoi(i_axis, axis);
109 addAxisData(axis_name, P_roi_axis->getMin(), P_roi_axis->getMax(), defaultUnits(),
112 addAxisData(axis_name, axis.getMin(), axis.getMax(), defaultUnits(), axis.size());
122 throw std::runtime_error(
"Error in SphericalConverter constructor: "
123 "detector has wrong dimension: "
124 + std::to_string(
static_cast<int>(detector.
dimension())));
125 addDetectorAxis(detector, 0);
126 addDetectorAxis(detector, 1);
129 SphericalConverter::~SphericalConverter() =
default;
139 result.push_back(Axes::Units::QSPACE);
143 Axes::Units SphericalConverter::defaultUnits()
const
145 return Axes::Units::DEGREES;
152 double SphericalConverter::calculateValue(
size_t i_axis, Axes::Units units_type,
double value)
const
154 switch (units_type) {
155 case Axes::Units::RADIANS:
157 case Axes::Units::DEGREES:
158 return Units::rad2deg(value);
159 case Axes::Units::QSPACE: {
163 return (k_i - k_f).y();
164 }
else if (i_axis == 1) {
166 return (k_f - k_i).z();
168 throw std::runtime_error(
"Error in SphericalConverter::calculateValue: "
169 "incorrect axis index: "
170 + std::to_string(
static_cast<int>(i_axis)));
172 case Axes::Units::QXQY: {
176 return (k_i - k_f).y();
177 }
else if (i_axis == 1) {
179 return (k_f - k_i).x();
181 throw std::runtime_error(
"Error in SphericalConverter::calculateValue: "
182 "incorrect axis index: "
183 + std::to_string(
static_cast<int>(i_axis)));
186 throwUnitsError(
"SphericalConverter::calculateValue",
availableUnits());
190 std::vector<std::map<Axes::Units, std::string>> SphericalConverter::createNameMaps()
const
192 std::vector<std::map<Axes::Units, std::string>> result;
193 result.push_back(AxisNames::InitSphericalAxis0());
194 result.push_back(AxisNames::InitSphericalAxis1());
204 throw std::runtime_error(
"Error in RectangularConverter constructor: "
205 "detector has wrong dimension: "
206 + std::to_string(
static_cast<int>(detector.
dimension())));
207 addDetectorAxis(detector, 0);
208 addDetectorAxis(detector, 1);
209 mP_detector_pixel.reset(detector.regionOfInterestPixel());
212 RectangularConverter::~RectangularConverter() =
default;
222 result.push_back(Axes::Units::QSPACE);
223 result.push_back(Axes::Units::MM);
227 Axes::Units RectangularConverter::defaultUnits()
const
229 return Axes::Units::MM;
237 double RectangularConverter::calculateValue(
size_t i_axis, Axes::Units units_type,
240 if (units_type == Axes::Units::MM)
242 const auto k00 = mP_detector_pixel->getPosition(0.0, 0.0);
243 const auto k01 = mP_detector_pixel->getPosition(0.0, 1.0);
244 const auto k10 = mP_detector_pixel->getPosition(1.0, 0.0);
245 const auto& max_pos = i_axis == 0 ? k10 : k01;
246 const double shift = value - m_axis_data_table[i_axis].min;
247 const auto k_f = normalizeToWavelength(k00 + shift * (max_pos - k00).unit());
248 switch (units_type) {
249 case Axes::Units::RADIANS:
250 return axisAngle(i_axis, k_f);
251 case Axes::Units::DEGREES:
252 return Units::rad2deg(axisAngle(i_axis, k_f));
253 case Axes::Units::QSPACE: {
256 return (k_i - k_f).y();
257 }
else if (i_axis == 1) {
258 return (k_f - k_i).z();
260 throw std::runtime_error(
"Error in RectangularConverter::calculateValue: "
261 "incorrect axis index: "
262 + std::to_string(
static_cast<int>(i_axis)));
264 case Axes::Units::QXQY: {
267 return (k_i - k_f).y();
268 }
else if (i_axis == 1) {
269 return (k_f - k_i).x();
271 throw std::runtime_error(
"Error in RectangularConverter::calculateValue: "
272 "incorrect axis index: "
273 + std::to_string(
static_cast<int>(i_axis)));
276 throwUnitsError(
"RectangularConverter::calculateValue",
availableUnits());
280 std::vector<std::map<Axes::Units, std::string>> RectangularConverter::createNameMaps()
const
282 std::vector<std::map<Axes::Units, std::string>> result;
283 result.push_back(AxisNames::InitRectangularAxis0());
284 result.push_back(AxisNames::InitRectangularAxis1());
290 if (m_wavelength <= 0.0)
291 throw std::runtime_error(
"Error in RectangularConverter::normalizeToWavelength: "
293 double K = M_TWOPI / m_wavelength;
294 return vector.
unit() * K;
297 double RectangularConverter::axisAngle(
size_t i_axis,
kvector_t k_f)
const
301 }
else if (i_axis == 1) {
302 return M_PI_2 - k_f.
theta();
304 throw std::runtime_error(
"Error in RectangularConverter::axisAngle: "
305 "incorrect axis index: "
306 + std::to_string(
static_cast<int>(i_axis)));
311 OffSpecularConverter::OffSpecularConverter(
const IDetector2D& detector,
const Beam& beam,
312 const IAxis& alpha_axis)
316 throw std::runtime_error(
"Error in OffSpecularConverter constructor: "
317 "detector has wrong dimension: "
318 + std::to_string(
static_cast<int>(detector.
dimension())));
319 addAxisData(axisName(0), alpha_axis.
getMin(), alpha_axis.
getMax(), defaultUnits(),
321 addDetectorYAxis(detector);
324 OffSpecularConverter::~OffSpecularConverter() =
default;
331 Axes::Units OffSpecularConverter::defaultUnits()
const
333 return Axes::Units::DEGREES;
341 double OffSpecularConverter::calculateValue(
size_t, Axes::Units units_type,
double value)
const
343 switch (units_type) {
344 case Axes::Units::RADIANS:
346 case Axes::Units::DEGREES:
347 return Units::rad2deg(value);
349 throwUnitsError(
"OffSpecularConverter::calculateValue",
availableUnits());
353 std::vector<std::map<Axes::Units, std::string>> OffSpecularConverter::createNameMaps()
const
355 std::vector<std::map<Axes::Units, std::string>> result;
356 result.push_back(AxisNames::InitOffSpecAxis0());
357 result.push_back(AxisNames::InitOffSpecAxis1());
361 void OffSpecularConverter::addDetectorYAxis(
const IDetector2D& detector)
363 const auto& axis = detector.getAxis(1);
365 const auto& axis_name = axisName(1);
366 std::unique_ptr<IAxis> P_new_axis;
368 P_new_axis = p_roi->clipAxisToRoi(1, axis);
370 P_new_axis.reset(axis.clone());
373 throw std::runtime_error(
"Error in OffSpecularConverter::addDetectorYAxis: "
374 "could not retrieve the y-axis of the detector");
376 std::unique_ptr<RectangularPixel> P_det_pixel(P_rect_det->regionOfInterestPixel());
377 const auto k00 = P_det_pixel->getPosition(0.0, 0.0);
378 const auto k01 = P_det_pixel->getPosition(0.0, 1.0);
379 const double alpha_f_min = M_PI_2 - k00.theta();
380 const double alpha_f_max = M_PI_2 - k01.theta();
381 addAxisData(axis_name, alpha_f_min, alpha_f_max, defaultUnits(), P_new_axis->size());
383 const double alpha_f_min = P_new_axis->getMin();
384 const double alpha_f_max = P_new_axis->getMax();
385 addAxisData(axis_name, alpha_f_min, alpha_f_max, defaultUnits(), P_new_axis->size());
387 throw std::runtime_error(
"Error in OffSpecularConverter::addDetectorYAxis: "
388 "wrong detector type");
394 const std::string z_axis_name =
"Position [nm]";
396 DepthProbeConverter::DepthProbeConverter(
const Beam& beam,
const IAxis& alpha_axis,
400 const auto& alpha_axis_name = axisName(0);
401 const auto& z_axis_name = axisName(1);
402 addAxisData(alpha_axis_name, alpha_axis.
getMin(), alpha_axis.
getMax(), defaultUnits(),
404 addAxisData(z_axis_name, z_axis.
getMin(), z_axis.
getMax(), defaultUnits(), z_axis.
size());
407 DepthProbeConverter::~DepthProbeConverter() =
default;
417 result.push_back(Axes::Units::QSPACE);
426 double DepthProbeConverter::calculateValue(
size_t i_axis, Axes::Units units_type,
429 checkUnits(units_type);
432 switch (units_type) {
433 case Axes::Units::DEGREES:
434 return Units::rad2deg(value);
435 case Axes::Units::QSPACE:
436 return getQ(m_wavelength, value);
442 std::vector<std::map<Axes::Units, std::string>> DepthProbeConverter::createNameMaps()
const
444 std::vector<std::map<Axes::Units, std::string>> result;
445 result.push_back(AxisNames::InitSpecAxis());
446 result.push_back(AxisNames::InitSampleDepthAxis());
450 void DepthProbeConverter::checkUnits(Axes::Units units_type)
const
453 if (std::find(available_units.begin(), available_units.end(), units_type)
454 == available_units.cend())
455 throwUnitsError(
"DepthProbeConverter::checkUnits", available_units);
Defines namespace AxisNames.
BasicVector3D< double > vecOfLambdaAlphaPhi(double _lambda, double _alpha, double _phi)
Creates a vector<double> as a wavevector with given wavelength and angles.
Defines M_PI and some more mathematical constants.
Defines class RectangularDetector.
Defines class RectangularPixel.
Defines class RegionOfInterest.
Defines interface UnitConverterSimple and its subclasses.
Defines class SphericalDetector.
Defines some unit conversion factors and other constants in namespace Units.
BasicVector3D< T > unit() const
Returns unit vector in direction of this. Throws for null vector.
double theta() const
Returns polar angle.
double phi() const
Returns azimuth angle.
Beam defined by wavelength, direction and intensity.
DepthProbeConverter class handles the unit translations for depth probe simulations Its default units...
std::vector< Axes::Units > availableUnits() const final
Returns the list of all available units.
Interface for one-dimensional axes.
virtual double getMin() const =0
Returns value of first point of axis.
virtual size_t size() const =0
retrieve the number of bins
virtual double getMax() const =0
Returns value of last point of axis.
Abstract 2D detector interface.
const RegionOfInterest * regionOfInterest() const override
Returns region of interest if exists.
Abstract detector interface.
size_t dimension() const
Returns actual dimensionality of the detector (number of defined axes)
virtual const RegionOfInterest * regionOfInterest() const =0
Returns region of interest if exists.
IUnitConverter class that handles the unit translations for off-specular simulations with a spherical...
IUnitConverter class that handles the unit translations for rectangular detectors Its default units a...
std::vector< Axes::Units > availableUnits() const final
Returns the list of all available units.
A flat rectangular detector with axes and resolution function.
IUnitConverter class that handles the unit translations for spherical detectors Its default units are...
std::vector< Axes::Units > availableUnits() const final
Returns the list of all available units.
A spherical detector with axes and resolution function.
Interface for objects that provide axis translations to different units for IDetector objects.
std::vector< Axes::Units > availableUnits() const override
Returns the list of all available units.