File: DepthprobeSimulation.cpp

package info (click to toggle)
bornagain 23.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 103,948 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 (167 lines) | stat: -rw-r--r-- 5,901 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sim/Simulation/DepthprobeSimulation.cpp
//! @brief     Implements class DepthprobeSimulation.
//!
//! @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/Simulation/DepthprobeSimulation.h"
#include "Base/Axis/Frame.h"
#include "Base/Axis/Scale.h"
#include "Base/Progress/ProgressHandler.h"
#include "Base/Util/Assert.h"
#include "Base/Vector/GisasDirection.h"
#include "Device/Beam/IFootprint.h"
#include "Device/Data/Datafield.h"
#include "Resample/Element/IElement.h"
#include "Resample/Element/ScanElement.h"
#include "Resample/Flux/ScalarFlux.h"
#include "Resample/Processed/ReSample.h"
#include "Sim/Scan/AlphaScan.h"
#include <numbers>
#include <valarray>

using std::numbers::pi;

const int ZDirection_None = 0;
const int ZDirection_Reflected = 1;
const int ZDirection_Transmitted = 2;
const int WaveProperty_Intensity = 0;
const int WaveProperty_Modulus = 4;
const int WaveProperty_Phase = 8;

DepthprobeSimulation::DepthprobeSimulation(const BeamScan& scan, const Sample& sample,
                                           const Scale& zaxis, int flags)
    : ISimulation(sample)
    , m_scan(scan.clone())
    , m_z_axis(zaxis.clone())
    , m_flags(flags)
{
}

DepthprobeSimulation::~DepthprobeSimulation() = default;

std::vector<const INode*> DepthprobeSimulation::nodeChildren() const
{
    std::vector<const INode*> result = ISimulation::nodeChildren();
    result.push_back(m_scan.get());
    return result;
}

//... Overridden executors:

void DepthprobeSimulation::initScanElementVector()
{
    m_eles = m_scan->generateElements();
}

void DepthprobeSimulation::runComputation(const ReSample& re_sample, size_t i, double weight)
{
    const size_t Nz = m_z_axis->size();
    ASSERT(m_cache.size() / Nz == m_eles.size());

    std::valarray<double> z_intensities; //!< simulated intensity for given z positions
    z_intensities.resize(Nz, 0.0);

    ScanElement& scan_ele = *(m_eles.begin() + static_cast<long>(i));

    const R3 ki = scan_ele.k();

    if (scan_ele.isCalculated() && ki.z() < 0) {
        const size_t n_layers = re_sample.numberOfSlices();
        size_t start_z_ind = Nz;

        const R3 ki = scan_ele.k();
        const Fluxes fluxes = re_sample.fluxesIn(ki);

        double z_layer_bottom(0.0);
        double z_layer_top(0.0);
        for (size_t i_layer = 0; i_layer < n_layers && start_z_ind != 0; ++i_layer) {
            z_layer_bottom = re_sample.avgeSlice(i_layer).low();
            z_layer_top = i_layer ? re_sample.avgeSlice(i_layer).hig() : z_layer_bottom;

            // get R & T coefficients for current layer
            const auto* flux = dynamic_cast<const ScalarFlux*>(fluxes[i_layer]);
            ASSERT(flux);
            const complex_t R = flux->getScalarR();
            const complex_t T = flux->getScalarT();
            const complex_t kz_out = flux->getScalarKz();
            const complex_t kz_in = -kz_out;

            // Compute intensity for z's of the layer
            size_t ip1_z = start_z_ind;
            for (; ip1_z > 0; --ip1_z) {
                const size_t i_z = ip1_z - 1;
                if (i_layer + 1 != n_layers && m_z_axis->binCenter(i_z) <= z_layer_bottom)
                    break;
                const double z = m_z_axis->binCenter(i_z) - z_layer_top;
                complex_t psi;
                if ((m_flags & 3) == ZDirection_None)
                    psi = R * exp_I(kz_out * z) + T * exp_I(kz_in * z);
                else if (m_flags & ZDirection_Reflected)
                    psi = R * exp_I(kz_out * z);
                else if (m_flags & ZDirection_Transmitted)
                    psi = T * exp_I(kz_in * z);
                else
                    throw std::runtime_error("Invalid combination of ZDirection flags");
                if ((m_flags & 12) == WaveProperty_Intensity)
                    z_intensities[i_z] = std::norm(psi);
                else if (m_flags & WaveProperty_Modulus)
                    z_intensities[i_z] = std::abs(psi);
                else if (m_flags & WaveProperty_Phase)
                    z_intensities[i_z] = std::arg(psi);
                else
                    throw std::runtime_error("Invalid combination of WaveProperty flags");
            }
            start_z_ind = ip1_z;
        }
    }

    for (double& v : z_intensities)
        v *= scan_ele.beamIntensity();

    for (size_t j = 0; j < Nz; ++j)
        m_cache[j * m_scan->nElements() + i] += z_intensities[j] * weight * scan_ele.weight();

    progress().incrementDone(1);
}

//... Overridden getters:

size_t DepthprobeSimulation::nElements() const
{
    return m_scan->nElements();
}

size_t DepthprobeSimulation::nOutChannels() const
{
    return nElements() * m_z_axis->size();
}

Datafield DepthprobeSimulation::packResult() const
{
    const size_t Nz = m_z_axis->size();
    const size_t Ns = m_scan->nScan();
    const size_t Nslong = m_scan->nElements();
    std::vector<double> out(Ns * Nz, 0.0);

    for (size_t j = 0; j < Nz; ++j)
        for (size_t i = 0; i < Nslong; ++i) {
            const ScanElement& ele = m_eles.at(i);
            const size_t i_real = ele.i_out();
            out[j * Ns + i_real] += m_cache[j * Nslong + i];
        }

    if (background())
        throw std::runtime_error("nonzero background is not supported by DepthprobeSimulation");

    std::vector<const Scale*> axes{m_scan->coordinateAxis()->clone(), m_z_axis->clone()};
    return {axes, out};
}