File: QzScan.cpp

package info (click to toggle)
bornagain 23.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 103,936 kB
  • sloc: cpp: 423,131; python: 40,997; javascript: 11,167; awk: 630; sh: 318; ruby: 173; xml: 130; makefile: 51; ansic: 24
file content (140 lines) | stat: -rw-r--r-- 4,830 bytes parent folder | download
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;
}