BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
InterferenceRadialParaCrystal.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sample/Aggregate/InterferenceRadialParaCrystal.cpp
6 //! @brief Implements class InterferenceRadialParaCrystal.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Fit/Param/RealLimits.h"
17 #include <limits>
18 
19 //! Constructor of interference function of radial paracrystal.
20 //! @param peak_distance: average distance to the next neighbor in nanometers
21 //! @param damping_length: the damping (coherence) length of the paracrystal in nanometers
23  double damping_length)
24  : IInterference(0)
25  , m_peak_distance(peak_distance)
26  , m_damping_length(damping_length)
27  , m_use_damping_length(true)
28  , m_kappa(0.0)
29  , m_domain_size(0.0)
30 {
31  if (m_damping_length == 0.0)
32  m_use_damping_length = false;
33 
36  RealLimits::nonnegative().check("SizeSpaceCoupling", m_kappa);
38 }
39 
41 {
43  result->setPositionVariance(m_position_var);
44  if (m_pdf)
45  result->setProbabilityDistribution(*m_pdf);
46  result->setKappa(m_kappa);
47  result->setDomainSize(m_domain_size);
48  return result;
49 }
50 
51 //! Sets size spacing coupling parameter of the Size Spacing Correlation Approximation.
53 {
54  m_kappa = kappa;
55 }
56 
58 {
59  return m_kappa;
60 }
61 
62 //! Sets domain size (finite size corrections).
63 //! @param size: size of coherence domain along the lattice main axis in nanometers
64 
66 {
67  m_domain_size = size;
68 }
69 
70 complex_t InterferenceRadialParaCrystal::FTPDF(double qpar) const
71 {
72  complex_t phase = exp_I(qpar * m_peak_distance);
73  double amplitude = m_pdf->standardizedFT(qpar);
74  complex_t result = phase * amplitude;
76  result *= std::exp(-m_peak_distance / m_damping_length);
77  return result;
78 }
79 
80 //! Sets one-dimensional probability distribution.
81 //! @param pdf: probability distribution (Fourier transform of probability density)
82 
84 {
85  m_pdf.reset(pdf.clone());
86 }
87 
88 std::vector<const INode*> InterferenceRadialParaCrystal::nodeChildren() const
89 {
90  return std::vector<const INode*>() << m_pdf;
91 }
92 
94 {
95  if (!m_pdf)
96  throw std::runtime_error("InterferenceRadialParaCrystal::"
97  "evaluate() -> Error! Probability distribution for "
98  "interference function not properly initialized");
99  double result = 0.0;
100  double qxr = q.x();
101  double qyr = q.y();
102  double qpar = std::sqrt(qxr * qxr + qyr * qyr);
103  int n = static_cast<int>(std::abs(m_domain_size / m_peak_distance));
104  auto nd = static_cast<double>(n);
105  complex_t fp = FTPDF(qpar);
106  if (n < 1) {
107  if (std::abs(1.0 - fp) < 10. * std::numeric_limits<double>::epsilon())
108  result = m_pdf->qSecondDerivative() / m_peak_distance / m_peak_distance;
109  else
110  result = ((1.0 + fp) / (1.0 - fp)).real();
111  } else {
112  if (std::norm(1.0 - fp) < 10. * std::numeric_limits<double>::epsilon())
113  result = nd;
114  // for (1-fp)*nd small, take the series expansion to second order in nd*(1-fp)
115  else if (std::abs(1.0 - fp) * nd < 2e-4) {
116  complex_t intermediate =
117  (nd - 1.0) / 2.0 + (nd * nd - 1.0) * (fp - 1.0) / 6.0
118  + (nd * nd * nd - 2.0 * nd * nd - nd + 2.0) * (fp - 1.0) * (fp - 1.0) / 24.0;
119  result = 1.0 + 2.0 * intermediate.real();
120  } else {
121  complex_t tmp;
122  if (std::abs(fp) == 0.0
123  || std::log(std::abs(fp)) * nd < std::log(std::numeric_limits<double>::min())) {
124  tmp = 0.0;
125  } else {
126  tmp = std::pow(fp, n);
127  }
128  complex_t intermediate =
129  fp / (1.0 - fp) - fp * (1.0 - tmp) / nd / (1.0 - fp) / (1.0 - fp);
130  result = 1.0 + 2.0 * intermediate.real();
131  }
132  }
133  return result;
134 }
Defines class InterferenceRadialParaCrystal.
Defines class RealLimits.
Abstract base class of interference functions.
Definition: IInterference.h:24
double m_position_var
Definition: IInterference.h:53
Interface for a one-dimensional distribution, with normalization adjusted so that the Fourier transfo...
Definition: Profiles1D.h:29
IProfile1D * clone() const override=0
Interference function of radial paracrystal.
double iff_without_dw(R3 q) const override
Calculates the structure factor without Debye-Waller factor.
double m_kappa
Size-spacing coupling parameter.
double m_domain_size
Size of coherence domain.
std::vector< const INode * > nodeChildren() const override
Returns all children.
InterferenceRadialParaCrystal * clone() const override
std::unique_ptr< IProfile1D > m_pdf
InterferenceRadialParaCrystal(double peak_distance, double damping_length)
Constructor of interference function of radial paracrystal.
void setKappa(double kappa)
Sets size spacing coupling parameter of the Size Spacing Correlation Approximation.
void setDomainSize(double size)
Sets domain size (finite size corrections).
void setProbabilityDistribution(const IProfile1D &pdf)
Sets one-dimensional probability distribution.
double m_damping_length
damping length of paracrystal Fourier transformed probability distribution of the nearest particle
double m_peak_distance
the distance to the first neighbor peak
void check(const std::string &name, double value) const
Throws if value is outside limits. Parameter 'name' is for exception message.
Definition: RealLimits.cpp:170
static RealLimits nonnegative()
Creates an object which can have only positive values with 0. included.
Definition: RealLimits.cpp:124