File: IDistribution1DSampler.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 (102 lines) | stat: -rw-r--r-- 3,378 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
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Correlation/IDistribution1DSampler.cpp
//! @brief     Defines class interface IProfile1D, and children thereof.
//!
//! @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 "Sample/Correlation/IDistribution1DSampler.h"
#include <numbers>
#include <random>

using std::numbers::pi;

IDistribution1DSampler::~IDistribution1DSampler() = default;

double Distribution1DCauchySampler::randomSample(int seed) const
{
    // BornAgain Cauchy Distribution = std library Exponential distribution
    std::random_device rd;                    // random device class instance
    std::mt19937 gen(seed < 0 ? rd() : seed); // Standard mersenne_twister_engine seeded with rd()
    std::exponential_distribution<double> expDist(m_lambda);
    double value = expDist(gen);

    std::bernoulli_distribution bernoulliDist(0.5);
    bool sign = bernoulliDist(gen);

    return sign ? value : -value;
}

double Distribution1DGaussSampler::randomSample(int seed) const
{
    // BornAgain Gauss Distribution = std library Normal distribution
    std::random_device rd;
    std::mt19937 gen(seed < 0 ? rd() : seed);
    std::normal_distribution<double> normalDist(m_mean, m_stddev);

    return normalDist(gen);
}

double Distribution1DGateSampler::randomSample(int seed) const
{
    // BornAgain Gate Distribution = std library Uniform distribution
    std::random_device rd;
    std::mt19937 gen(seed < 0 ? rd() : seed);
    std::uniform_real_distribution<double> uniformDist(m_a, m_b);

    return uniformDist(gen);
}

double Distribution1DTriangleSampler::randomSample(int seed) const
{
    std::random_device rd;
    std::mt19937 gen(seed < 0 ? rd() : seed);

    // generate a cdf value between 0 and 1
    std::uniform_real_distribution<> uniformDist(0.0, 1.0);
    double cdf_value = uniformDist(gen);

    // solve for x by inverting the cdf of Triangle Distribution
    if (cdf_value <= 0.5)
        return (-m_omega + m_omega * std::sqrt(2 * cdf_value));
    return (m_omega - m_omega * std::sqrt(2 * (1 - cdf_value)));
}

double Distribution1DCosineSampler::randomSample(int seed) const
{
    std::random_device rd;
    std::mt19937 gen(seed < 0 ? rd() : seed);

    // generate a cdf value between 0 and 1
    std::uniform_real_distribution<> uniformDist(0.0, 1.0);
    double cdf_value = uniformDist(gen);

    // solve for x from the cdf of Cosine Distribution using Newton-Raphson method
    double func = 0.0, funcDeriv = 0.0, x = 0.0;

    // initial guess for x
    if (cdf_value <= 0.5)
        x = -m_omega / 2;
    else
        x = m_omega / 2;

    bool convergedSoln = false;
    while (!convergedSoln) {
        func = x + m_omega / pi * std::sin(pi * x / m_omega) + m_omega * (1 - 2 * cdf_value);
        funcDeriv = 1 + std::cos(pi * x / m_omega);

        x = x - func / funcDeriv;

        if (std::abs(func / funcDeriv) < 0.001)
            convergedSoln = true;
    }

    return x;
}