BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
InterferenceFunctionRadialParaCrystal.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sample/Aggregate/InterferenceFunctionRadialParaCrystal.cpp
6 //! @brief Implements class InterferenceFunctionRadialParaCrystal.
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 
18 #include <limits>
19 
20 //! Constructor of interference function of radial paracrystal.
21 //! @param peak_distance: average distance to the next neighbor in nanometers
22 //! @param damping_length: the damping (coherence) length of the paracrystal in nanometers
24  double damping_length)
26  , m_peak_distance(peak_distance)
27  , m_damping_length(damping_length)
28  , m_use_damping_length(true)
29  , m_kappa(0.0)
30  , m_domain_size(0.0)
31 {
32  setName("InterferenceRadialParaCrystal");
33  if (m_damping_length == 0.0)
34  m_use_damping_length = false;
35  registerParameter("PeakDistance", &m_peak_distance).setUnit("nm").setNonnegative();
36  registerParameter("DampingLength", &m_damping_length).setUnit("nm").setNonnegative();
37  registerParameter("SizeSpaceCoupling", &m_kappa).setNonnegative();
38  registerParameter("DomainSize", &m_domain_size).setUnit("nm").setNonnegative();
39 }
40 
42 {
44  ret->setPositionVariance(m_position_var);
45  if (m_pdf)
46  ret->setProbabilityDistribution(*m_pdf);
47  ret->setKappa(m_kappa);
48  ret->setDomainSize(m_domain_size);
49  return ret;
50 }
51 
52 //! Sets size spacing coupling parameter of the Size Spacing Correlation Approximation.
54 {
55  m_kappa = kappa;
56 }
57 
59 {
60  return m_kappa;
61 }
62 
63 //! Sets domain size (finite size corrections).
64 //! @param size: size of coherence domain along the lattice main axis in nanometers
65 
67 {
68  m_domain_size = size;
69 }
70 
72 {
73  complex_t phase = exp_I(qpar * m_peak_distance);
74  double amplitude = m_pdf->evaluate(qpar);
75  complex_t result = phase * amplitude;
77  result *= std::exp(-m_peak_distance / m_damping_length);
78  return result;
79 }
80 
81 //! Sets one-dimensional probability distribution.
82 //! @param pdf: probability distribution (Fourier transform of probability density)
83 
85 {
86  m_pdf.reset(pdf.clone());
87  registerChild(m_pdf.get());
88 }
89 
90 std::vector<const INode*> InterferenceFunctionRadialParaCrystal::getChildren() const
91 {
92  return std::vector<const INode*>() << m_pdf;
93 }
94 
96 {
97  if (!m_pdf)
98  throw std::runtime_error("InterferenceFunctionRadialParaCrystal::"
99  "evaluate() -> Error! Probability distribution for "
100  "interference function not properly initialized");
101  double result = 0.0;
102  double qxr = q.x();
103  double qyr = q.y();
104  double qpar = std::sqrt(qxr * qxr + qyr * qyr);
105  int n = static_cast<int>(std::abs(m_domain_size / m_peak_distance));
106  double nd = static_cast<double>(n);
107  complex_t fp = FTPDF(qpar);
108  if (n < 1) {
109  if (std::abs(1.0 - fp) < 10. * std::numeric_limits<double>::epsilon()) {
110  result = m_pdf->qSecondDerivative() / m_peak_distance / m_peak_distance;
111  } else {
112  result = ((1.0 + fp) / (1.0 - fp)).real();
113  }
114  } else {
115  if (std::norm(1.0 - fp) < 10. * std::numeric_limits<double>::epsilon()) {
116  result = nd;
117  }
118  // for (1-fp)*nd small, take the series expansion to second order in nd*(1-fp)
119  else if (std::abs(1.0 - fp) * nd < 2e-4) {
120  complex_t intermediate =
121  (nd - 1.0) / 2.0 + (nd * nd - 1.0) * (fp - 1.0) / 6.0
122  + (nd * nd * nd - 2.0 * nd * nd - nd + 2.0) * (fp - 1.0) * (fp - 1.0) / 24.0;
123  result = 1.0 + 2.0 * intermediate.real();
124  } else {
125  complex_t tmp;
126  if (std::abs(fp) == 0.0
127  || std::log(std::abs(fp)) * nd < std::log(std::numeric_limits<double>::min())) {
128  tmp = 0.0;
129  } else {
130  tmp = std::pow(fp, n);
131  }
132  complex_t intermediate =
133  fp / (1.0 - fp) - fp * (1.0 - tmp) / nd / (1.0 - fp) / (1.0 - fp);
134  result = 1.0 + 2.0 * intermediate.real();
135  }
136  }
137  return result;
138 }
std::complex< double > complex_t
Definition: Complex.h:20
complex_t exp_I(complex_t z)
Returns exp(I*z), where I is the imaginary unit.
Definition: Complex.h:30
Defines class InterferenceFunctionRadialParaCrystal.
Defines class ParameterPool.
Defines class RealParameter.
T y() const
Returns y-component in cartesian coordinate system.
Definition: BasicVector3D.h:65
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:63
Interface for a one-dimensional distribution, with normalization adjusted so that the Fourier transfo...
virtual IFTDistribution1D * clone() const =0
Abstract base class of interference functions.
void registerChild(INode *node)
Definition: INode.cpp:57
void setName(const std::string &name)
RealParameter & registerParameter(const std::string &name, double *parpointer)
Interference function of radial paracrystal.
InterferenceFunctionRadialParaCrystal * clone() const final
Returns a clone of this ISampleNode object.
InterferenceFunctionRadialParaCrystal(double peak_distance, double damping_length)
Constructor of interference function of radial paracrystal.
void setDomainSize(double size)
Sets domain size (finite size corrections).
double iff_without_dw(const kvector_t q) const final
Calculates the structure factor without Debye-Waller factor.
std::vector< const INode * > getChildren() const final
Returns a vector of children.
void setKappa(double kappa)
Sets size spacing coupling parameter of the Size Spacing Correlation Approximation.
std::unique_ptr< IFTDistribution1D > m_pdf
Fourier transformed probability distribution of the nearest particle.
double m_peak_distance
the distance to the first neighbor peak
void setProbabilityDistribution(const IFTDistribution1D &pdf)
Sets one-dimensional probability distribution.
RealParameter & setNonnegative()
RealParameter & setUnit(const std::string &name)