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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file Sim/Scan/QzScan.cpp
//! @brief Implements class QzScan.
//!
//! @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/QzScan.h"
#include "Base/Axis/MakeScale.h"
#include "Base/Axis/Scale.h"
#include "Base/Util/Assert.h"
#include "Device/Beam/Beam.h"
#include "Device/Pol/PolFilter.h"
#include "Param/Distrib/Distributions.h"
#include "Param/Distrib/ParameterSample.h"
#include "Resample/Element/ScanElement.h"
#include <algorithm> // is_sorted
#include <numbers>
using std::numbers::pi;
QzScan::QzScan(const Scale& qs_nm)
: BeamScan(qs_nm)
{
std::vector<double> axis_values = m_axis->binCenters();
if (!std::is_sorted(axis_values.begin(), axis_values.end()))
throw std::runtime_error("QzScan: q-vector values are not "
"sorted in ascending order.");
if (axis_values.front() < 0)
throw std::runtime_error("QzScan: negative q-values.");
m_beams.clear();
for (size_t i = 0; i < nScan(); i++) {
// Qz scan is internally understood as wavelength scan
double lambda = 4 * pi * std::sin(defaultGrazingAngle) / m_axis->binCenter(i);
auto* beam = new Beam(defaultIntensity, lambda, defaultGrazingAngle);
// Since the grazing geometry is not clear in q-space, the footprint should not be used
beam->setFootprint(nullptr);
m_beams.push_back(beam);
}
}
QzScan::QzScan(std::vector<double> qs_nm)
: QzScan(ListScan("q_z (1/nm)", std::move(qs_nm)))
{
}
QzScan::QzScan(int nbins, double qz_min, double qz_max)
: QzScan(EquiScan("q_z (1/nm)", nbins, qz_min, qz_max))
{
}
QzScan::~QzScan() = default;
QzScan* QzScan::clone() const
{
auto* result = new QzScan(*m_axis);
copyBeamScan(result);
if (m_qz_distrib) {
result->m_qz_distrib.reset(m_qz_distrib->clone());
result->m_resol_width_factor = m_resol_width_factor;
result->m_relative_resolution = m_relative_resolution;
}
result->setOffset(m_offset);
return result;
}
std::vector<const INode*> QzScan::nodeChildren() const
{
std::vector<const INode*> result;
for (const INode* n : BeamScan::nodeChildren())
result << n;
if (m_qz_distrib)
result << m_qz_distrib.get();
return result;
}
//! Generates simulation elements for specular simulations
std::vector<ScanElement> QzScan::generateElements() const
{
std::vector<ScanElement> result;
result.reserve(nDistributionSamples());
for (size_t i = 0; i < m_axis->size(); ++i) {
const double q0 = m_axis->binCenter(i);
if (m_qz_distrib) {
const std::vector<ParameterSample> qzDistrib = m_qz_distrib->distributionSamples();
for (auto j : qzDistrib) {
double qz = q0;
ASSERT(!m_resol_width_factor.empty());
if (m_relative_resolution)
qz += q0 * m_resol_width_factor[0] * j.value;
else if (m_resol_width_factor.size() > 1)
qz += m_resol_width_factor[i] * j.value;
else
qz += m_resol_width_factor[0] * j.value;
result.emplace_back(i, qz >= 0, j.weight, intensityAt(i), 1., polarizerMatrixAt(i),
analyzerMatrix(), 0, 0, 0, R3(0, 0, -(qz + m_offset) / 2));
}
} else {
result.emplace_back(i, q0 >= 0, 1., intensityAt(i), 1., polarizerMatrixAt(i),
analyzerMatrix(), 0, 0, 0, R3(0, 0, -(q0 + m_offset) / 2));
}
}
return result;
}
//! Returns the number of simulation elements
size_t QzScan::nDistributionSamples() const
{
return m_qz_distrib ? m_qz_distrib->nSamples() : 1;
}
void QzScan::setRelativeQResolution(const IDistribution1D& distr, double rel_dev)
{
m_qz_distrib.reset(distr.clone());
m_relative_resolution = true;
m_resol_width_factor = {rel_dev};
}
void QzScan::setAbsoluteQResolution(const IDistribution1D& distr, double std_dev)
{
m_qz_distrib.reset(distr.clone());
m_relative_resolution = false;
m_resol_width_factor = {std_dev};
}
void QzScan::setVectorResolution(const IDistribution1D& distr, const std::vector<double>& std_devs)
{
m_qz_distrib.reset(distr.clone());
m_relative_resolution = false;
ASSERT(std_devs.size() > 1);
m_resol_width_factor = std_devs;
}
|