File: InterferenceRadialParacrystal.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 (132 lines) | stat: -rw-r--r-- 4,862 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
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/Aggregate/InterferenceRadialParacrystal.cpp
//! @brief     Implements class InterferenceRadialParacrystal.
//!
//! @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/Aggregate/InterferenceRadialParacrystal.h"
#include "Base/Util/Assert.h"
#include <limits>

//! Constructor of interference function of radial paracrystal.
//! @param peak_distance: average distance to the next neighbor in nanometers
//! @param damping_length: the damping (coherence) length of the paracrystal in nanometers
InterferenceRadialParacrystal::InterferenceRadialParacrystal(double peak_distance,
                                                             double damping_length)
    : IInterference(0)
    , m_peak_distance(peak_distance)
    , m_damping_length(damping_length)
    , m_kappa(0.0)
    , m_domain_size(0.0)
{
    validateOrThrow();
}

InterferenceRadialParacrystal* InterferenceRadialParacrystal::clone() const
{
    auto* result = new InterferenceRadialParacrystal(m_peak_distance, m_damping_length);
    result->setPositionVariance(m_position_var);
    if (m_pdf)
        result->setProbabilityDistribution(*m_pdf);
    result->setKappa(m_kappa);
    result->setDomainSize(m_domain_size);
    return result;
}

//! Sets size spacing coupling parameter of the Size Spacing Correlation Approximation.
void InterferenceRadialParacrystal::setKappa(double kappa)
{
    m_kappa = kappa;
}
//! Sets domain size (finite size corrections).
//! @param size: size of coherence domain along the lattice main axis in nanometers

void InterferenceRadialParacrystal::setDomainSize(double size)
{
    m_domain_size = size;
}

complex_t InterferenceRadialParacrystal::FTPDF(double qpar) const
{
    complex_t phase = exp_I(qpar * m_peak_distance);
    double amplitude = m_pdf->standardizedFT(qpar);
    complex_t result = phase * amplitude;
    if (m_damping_length)
        result *= std::exp(-m_peak_distance / m_damping_length);
    return result;
}

//! Sets one-dimensional probability distribution.
//! @param pdf: probability distribution (Fourier transform of probability density)

void InterferenceRadialParacrystal::setProbabilityDistribution(const IProfile1D& pdf)
{
    m_pdf.reset(pdf.clone());
}

std::vector<const INode*> InterferenceRadialParacrystal::nodeChildren() const
{
    return std::vector<const INode*>() << m_pdf;
}

double InterferenceRadialParacrystal::iff_without_dw(const R3& q) const
{
    ASSERT(m_validated);
    ASSERT(m_pdf);
    double result = 0.0;
    double qxr = q.x();
    double qyr = q.y();
    double qpar = std::sqrt(qxr * qxr + qyr * qyr);
    int n = static_cast<int>(std::abs(m_domain_size / m_peak_distance));
    auto nd = static_cast<double>(n);
    complex_t fp = FTPDF(qpar);
    if (n < 1) {
        if (std::abs(1.0 - fp) < 10. * std::numeric_limits<double>::epsilon())
            result = m_pdf->qSecondDerivative() / m_peak_distance / m_peak_distance;
        else
            result = ((1.0 + fp) / (1.0 - fp)).real();
    } else {
        if (std::norm(1.0 - fp) < 10. * std::numeric_limits<double>::epsilon())
            result = nd;
        // for (1-fp)*nd small, take the series expansion to second order in nd*(1-fp)
        else if (std::abs(1.0 - fp) * nd < 2e-4) {
            complex_t intermediate =
                (nd - 1.0) / 2.0 + (nd * nd - 1.0) * (fp - 1.0) / 6.0
                + (nd * nd * nd - 2.0 * nd * nd - nd + 2.0) * (fp - 1.0) * (fp - 1.0) / 24.0;
            result = 1.0 + 2.0 * intermediate.real();
        } else {
            complex_t tmp;
            if (std::abs(fp) == 0.0
                || std::log(std::abs(fp)) * nd < std::log(std::numeric_limits<double>::min())) {
                tmp = 0.0;
            } else {
                tmp = std::pow(fp, n);
            }
            complex_t intermediate =
                fp / (1.0 - fp) - fp * (1.0 - tmp) / nd / (1.0 - fp) / (1.0 - fp);
            result = 1.0 + 2.0 * intermediate.real();
        }
    }
    return result;
}

std::string InterferenceRadialParacrystal::validate() const
{
    std::vector<std::string> errs;
    requestGe0(errs, m_peak_distance, "PeakDistance");
    requestGe0(errs, m_damping_length, "DampingLength");
    requestGe0(errs, m_kappa, "SizeSpaceCoupling");
    requestGe0(errs, m_domain_size, "DomainSize");
    if (!errs.empty())
        return jointError(errs);
    m_validated = true;
    return "";
}