File: OffspecSimulation.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 (141 lines) | stat: -rw-r--r-- 4,713 bytes parent folder | download | duplicates (2)
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
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sim/Simulation/OffspecSimulation.cpp
//! @brief     Implements class OffspecSimulation.
//!
//! @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/OffspecSimulation.h"
#include "Base/Axis/Frame.h"
#include "Base/Axis/Pixel.h"
#include "Base/Axis/Scale.h"
#include "Base/Progress/ProgressHandler.h"
#include "Base/Util/Assert.h"
#include "Device/Beam/IFootprint.h"
#include "Device/Data/Datafield.h"
#include "Device/Detector/OffspecDetector.h"
#include "Resample/Element/DiffuseElement.h"
#include "Resample/Element/ScanElement.h"
#include "Sim/Background/IBackground.h"
#include "Sim/Computation/DWBAComputation.h"
#include "Sim/Scan/PhysicalScan.h"

OffspecSimulation::OffspecSimulation(const PhysicalScan& scan, const Sample& sample,
                                     const OffspecDetector& detector)
    : ISimulation(sample)
    , m_scan(scan.clone())
    , m_detector(detector.clone())
{
}

OffspecSimulation::~OffspecSimulation() = default;

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

void OffspecSimulation::prepareSimulation()
{
    m_pixels.reserve(m_detector->totalSize());
    for (size_t i = 0; i < m_detector->totalSize(); ++i)
        m_pixels.push_back(m_detector->createPixel(i));
}

//... Overridden executors:

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

void OffspecSimulation::runComputation(const ReSample& re_sample, size_t i, double weight)
{
    const size_t Na = m_detector->totalSize();
    size_t j = i / Na; // index in unwrapped scan (including distribution sampling)
    size_t k = i % Na; // index in detector

    ASSERT(m_cache.size() / Na == m_eles.size());

    ScanElement& scan_ele = *(m_eles.begin() + static_cast<long>(j));
    const double alpha_i = scan_ele.alpha();
    const double lambda_i = scan_ele.lambda();
    const double phi_i = scan_ele.phi();
    const bool isSpecular = k == m_detector->indexOfSpecular(alpha_i, phi_i);

    DiffuseElement diff_ele(lambda_i, alpha_i, phi_i, m_pixels[k],
                            m_scan->polarizerMatrixAt(scan_ele.i_out()),
                            m_detector->analyzer().matrix(), isSpecular);

    double intensity = Compute::scattered_and_reflected(re_sample, options(), diff_ele);

    double sin_alpha_i = std::abs(std::sin(alpha_i));
    if (sin_alpha_i == 0.0) {
        intensity = 0;
    } else {
        const double solid_angle = diff_ele.solidAngle();
        intensity *= scan_ele.beamIntensity() * scan_ele.footprint() * solid_angle / sin_alpha_i;
    }

    m_cache[i] += intensity * weight * scan_ele.weight();

    progress().incrementDone(1);
}

//... Overridden getters:

bool OffspecSimulation::force_polarized() const
{
    return m_detector->analyzer().BlochVector() != R3{};
}

size_t OffspecSimulation::nElements() const
{
    return m_detector->totalSize() * m_scan->nElements();
}

Datafield OffspecSimulation::packResult() const
{
    const size_t ns = m_scan->nScan();
    const size_t nslong = m_scan->nElements();

    const size_t nphi = m_detector->axis(0).size();
    const size_t nalp = m_detector->axis(1).size();
    const size_t Ndet = nalp * nphi;
    std::vector<double> out(ns * nalp, 0.);

    for (size_t j = 0; j < nslong; ++j) {
        for (size_t ia = 0; ia < nalp; ++ia) {
            double val = 0;

            // sum over detector phi to the distribution point
            for (size_t ip = 0; ip < nphi; ++ip)
                val += m_cache[j * Ndet + ia * nphi + ip];

            // accumulate distribution points to the scan point
            const ScanElement& ele = m_eles.at(j);
            const size_t j_real = ele.i_out();
            out[ia * ns + j_real] += val;
        }
    }

    // TODO restore resolution m_detector->applyDetectorResolution(&detector_image);

    if (background())
        for (double& o : out)
            o = background()->addBackground(o);

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