BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
RoughMultiLayerComputation.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Core/Computation/RoughMultiLayerComputation.cpp
6 //! @brief Implements class RoughMultiLayerComputation.
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 "Base/Math/Constants.h"
25 
26 #include <cerfcpp.h>
27 
28 // Diffuse scattering from rough interfaces is modelled after
29 // Phys. Rev. B, vol. 51 (4), p. 2311 (1995)
30 
31 namespace {
32 complex_t h_plus(complex_t z)
33 {
34  return 0.5 * cerfcx(-mul_I(z) / std::sqrt(2.0));
35 }
36 complex_t h_min(complex_t z)
37 {
38  return 0.5 * cerfcx(mul_I(z) / std::sqrt(2.0));
39 }
40 } // namespace
41 
43  : m_sample{p_sample}
44 {
45 }
46 
48 {
49  if (elem.getAlphaMean() < 0.0)
50  return;
51  auto n_slices = m_sample->numberOfSlices();
52  kvector_t q = elem.meanQ();
53  double wavelength = elem.wavelength();
54  double autocorr(0.0);
55  complex_t crosscorr(0.0, 0.0);
56 
57  std::vector<complex_t> rterm(n_slices - 1);
58  std::vector<complex_t> sterm(n_slices - 1);
59 
60  for (size_t i = 0; i + 1 < n_slices; i++) {
61  rterm[i] = get_refractive_term(i, wavelength);
62  sterm[i] = get_sum8terms(i, elem);
63  }
64  for (size_t i = 0; i + 1 < n_slices; i++) {
65  const LayerRoughness* rough = m_sample->bottomRoughness(i);
66  if (rough)
67  autocorr += std::norm(rterm[i]) * std::norm(sterm[i]) * rough->getSpectralFun(q);
68  }
69  // cross correlation between layers
70  if (m_sample->crossCorrelationLength() != 0.0) {
71  for (size_t j = 0; j < n_slices - 1; j++) {
72  for (size_t k = 0; k < n_slices - 1; k++) {
73  if (j == k)
74  continue;
75  crosscorr += rterm[j] * sterm[j] * m_sample->crossCorrSpectralFun(q, j, k)
76  * std::conj(rterm[k]) * std::conj(sterm[k]);
77  }
78  }
79  }
80  //! @TODO clarify complex vs double
81  elem.addIntensity((autocorr + crosscorr.real()) * M_PI / 4. / wavelength / wavelength);
82 }
83 
84 complex_t RoughMultiLayerComputation::get_refractive_term(size_t ilayer, double wavelength) const
85 {
86  auto& slices = m_sample->slices();
87  return slices[ilayer].material().refractiveIndex2(wavelength)
88  - slices[ilayer + 1].material().refractiveIndex2(wavelength);
89 }
90 
92  const SimulationElement& sim_element) const
93 {
94  auto& slices = m_sample->slices();
95  auto p_fresnel_map = m_sample->fresnelMap();
96  const auto P_in_plus = p_fresnel_map->getInCoefficients(sim_element, ilayer);
97  const auto P_out_plus = p_fresnel_map->getOutCoefficients(sim_element, ilayer);
98 
99  const auto P_in_minus = p_fresnel_map->getInCoefficients(sim_element, ilayer + 1);
100  const auto P_out_minus = p_fresnel_map->getOutCoefficients(sim_element, ilayer + 1);
101 
102  complex_t kiz_plus = P_in_plus->getScalarKz();
103  complex_t kfz_plus = P_out_plus->getScalarKz();
104  complex_t qz1_plus = -kiz_plus - kfz_plus;
105  complex_t qz2_plus = -kiz_plus + kfz_plus;
106  complex_t qz3_plus = -qz2_plus;
107  complex_t qz4_plus = -qz1_plus;
108  double thickness = slices[ilayer].thickness();
109  complex_t T_in_plus = P_in_plus->getScalarT() * exp_I(kiz_plus * thickness);
110  complex_t R_in_plus = P_in_plus->getScalarR() * exp_I(-kiz_plus * thickness);
111  complex_t T_out_plus = P_out_plus->getScalarT() * exp_I(kfz_plus * thickness);
112  complex_t R_out_plus = P_out_plus->getScalarR() * exp_I(-kfz_plus * thickness);
113 
114  complex_t kiz_minus = P_in_minus->getScalarKz();
115  complex_t kfz_minus = P_out_minus->getScalarKz();
116  complex_t qz1_minus = -kiz_minus - kfz_minus;
117  complex_t qz2_minus = -kiz_minus + kfz_minus;
118  complex_t qz3_minus = -qz2_minus;
119  complex_t qz4_minus = -qz1_minus;
120 
121  double sigma(0.0);
122  if (const LayerRoughness* roughness = m_sample->bottomRoughness(ilayer))
123  sigma = roughness->getSigma();
124  complex_t term1 = T_in_plus * T_out_plus * h_plus(qz1_plus * sigma);
125  complex_t term2 = T_in_plus * R_out_plus * h_plus(qz2_plus * sigma);
126  complex_t term3 = R_in_plus * T_out_plus * h_plus(qz3_plus * sigma);
127  complex_t term4 = R_in_plus * R_out_plus * h_plus(qz4_plus * sigma);
128  complex_t term5 =
129  P_in_minus->getScalarT() * P_out_minus->getScalarT() * h_min(qz1_minus * sigma);
130  complex_t term6 =
131  P_in_minus->getScalarT() * P_out_minus->getScalarR() * h_min(qz2_minus * sigma);
132  complex_t term7 =
133  P_in_minus->getScalarR() * P_out_minus->getScalarT() * h_min(qz3_minus * sigma);
134  complex_t term8 =
135  P_in_minus->getScalarR() * P_out_minus->getScalarR() * h_min(qz4_minus * sigma);
136 
137  return term1 + term2 + term3 + term4 + term5 + term6 + term7 + term8;
138 }
complex_t mul_I(complex_t z)
Returns product I*z, where I is the imaginary unit.
Definition: Complex.h:24
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 M_PI and some more mathematical constants.
#define M_PI
Definition: Constants.h:44
Defines interface IFresnelMap.
Defines and implements class ILayerRTCoefficients.
Defines class LayerInterface.
Defines class LayerRoughness.
Defines class Layer.
Defines class MultiLayer.
Defines class ProcessedSample.
Defines class RoughMultiLayerComputation.
Defines class SimulationElement.
std::unique_ptr< const ILayerRTCoefficients > getInCoefficients(const T &sim_element, size_t layer_index) const
Retrieves the amplitude coefficients for an incoming wavevector.
Definition: IFresnelMap.h:45
A roughness of interface between two layers.
double getSpectralFun(const kvector_t kvec) const
Returns power spectral density of the surface roughness.
Data structure that contains all the necessary data for scattering calculations.
const std::vector< Slice > & slices() const
const IFresnelMap * fresnelMap() const
size_t numberOfSlices() const
double crossCorrSpectralFun(const kvector_t kvec, size_t j, size_t k) const
Fourier transform of the correlation function of roughnesses between the interfaces.
double crossCorrelationLength() const
const LayerRoughness * bottomRoughness(size_t i) const
void compute(SimulationElement &elem) const
complex_t get_sum8terms(size_t ilayer, const SimulationElement &sim_element) const
complex_t get_refractive_term(size_t ilayer, double wavelength) const
RoughMultiLayerComputation(const ProcessedSample *p_sample)
Data stucture containing both input and output of a single detector cell.
double wavelength() const
void addIntensity(double intensity)
kvector_t meanQ() const
double getAlphaMean() const