1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file Sim/Scan/AlphaScan.cpp
//! @brief Implements class AlphaScan.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "Sim/Scan/AlphaScan.h"
#include "Base/Axis/MakeScale.h"
#include "Base/Axis/Scale.h"
#include "Base/Math/Numeric.h"
#include "Base/Vector/GisasDirection.h"
#include "Device/Beam/Beam.h"
#include "Device/Beam/IFootprint.h"
#include "Device/Pol/PolFilter.h"
#include "Param/Distrib/ParameterSample.h"
#include "Resample/Element/ScanElement.h"
#include <algorithm> // is_sorted
#include <numbers>
using std::numbers::pi;
AlphaScan::AlphaScan(const Scale& alpha_axis)
: PhysicalScan(alpha_axis)
{
const std::vector<double> axis_values = m_axis->binCenters();
if (!std::is_sorted(axis_values.begin(), axis_values.end()))
throw std::runtime_error("AlphaScan: angle values are not "
"sorted in ascending order.");
if (axis_values.front() < 0)
throw std::runtime_error("AlphaScan: negative angles.");
if (axis_values.back() > pi / 2)
throw std::runtime_error("AlphaScan: angles beyond normal.");
m_beams.clear();
for (size_t i = 0; i < nScan(); i++) {
auto* beam = new Beam(defaultIntensity, defaultWavelength, m_axis->binCenter(i));
m_beams.push_back(beam);
}
}
AlphaScan::AlphaScan(std::vector<double> points)
: AlphaScan(ListScan("alpha_i (rad)", std::move(points)))
{
}
AlphaScan::AlphaScan(int nbins, double alpha_i_min, double alpha_i_max)
: AlphaScan(EquiScan("alpha_i (rad)", nbins, alpha_i_min, alpha_i_max))
{
}
AlphaScan::~AlphaScan() = default;
AlphaScan* AlphaScan::clone() const
{
auto* result = new AlphaScan(*m_axis);
copyPhysicalScan(result);
result->setAlphaOffset(alphaOffset());
return result;
}
std::vector<ScanElement> AlphaScan::generateElements() const
{
std::vector<ScanElement> result;
result.reserve(nElements());
for (size_t i = 0; i < m_axis->size(); ++i) {
const std::vector<ParameterSample> alphaDistrib =
drawDistribution(m_alpha_distrib.get(), grazingAngleAt(i) + m_alpha_offset);
const std::vector<ParameterSample> lambdaDistrib =
drawDistribution(m_lambda_distrib.get(), wavelengthAt(i));
const std::vector<ParameterSample> phiDistrib =
drawDistribution(m_phi_distrib.get(), azimuthalAngleAt(i));
for (auto ad : alphaDistrib) {
const double alpha = ad.value;
for (auto ld : lambdaDistrib) {
const double lambda = ld.value;
for (auto pd : phiDistrib) {
const double phi = pd.value;
const R3 kvec = vecOfLambdaAlphaPhi(lambda, -alpha, -phi);
const bool computable =
lambda > 0 && alpha >= 0 && alpha <= (pi / 2) && kvec.z() <= 0;
const double weight = ad.weight * ld.weight * pd.weight;
const double footprint = footprintAt(i) ? footprintAt(i)->calculate(alpha) : 1;
result.emplace_back(i, computable, weight, intensityAt(i), footprint,
polarizerMatrixAt(i), analyzerMatrix(), lambda, alpha, phi,
kvec);
}
}
}
}
return result;
}
|