BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
RoughMultiLayerContribution.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sim/Contrib/RoughMultiLayerContribution.cpp
6 //! @brief Implements class RoughMultiLayerContribution.
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"
17 #include "Base/Util/Assert.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 
33 complex_t h_plus(complex_t z)
34 {
35  return 0.5 * cerfcx(-mul_I(z) / std::sqrt(2.0));
36 }
37 complex_t h_min(complex_t z)
38 {
39  return 0.5 * cerfcx(mul_I(z) / std::sqrt(2.0));
40 }
41 
42 } // namespace
43 
44 
46  : m_re_sample{re_sample}
47 {
48 }
49 
51 {
52  if (ele.alphaMean() < 0.0)
53  return;
54  const size_t n_slices = m_re_sample.numberOfSlices();
55  R3 q = ele.meanQ();
56  double wavelength = ele.wavelength();
57  double autocorr(0.0);
58  complex_t crosscorr(0.0, 0.0);
59 
60  std::vector<complex_t> rterm(n_slices - 1);
61  std::vector<complex_t> sterm(n_slices - 1);
62 
63  for (size_t i = 0; i + 1 < n_slices; i++) {
64  rterm[i] = get_refractive_term(i, wavelength);
65  sterm[i] = get_sum8terms(i, ele);
66  }
67  for (size_t i = 0; i + 1 < n_slices; i++) {
68  const LayerRoughness* rough = m_re_sample.avgeSlice(i + 1).topRoughness();
69  if (rough)
70  autocorr += std::norm(rterm[i]) * std::norm(sterm[i]) * rough->spectralFunction(q);
71  }
72  // cross correlation between layers
73  if (m_re_sample.sample().crossCorrLength() != 0.0) {
74  for (size_t j = 0; j < n_slices - 1; j++) {
75  for (size_t k = 0; k < n_slices - 1; k++) {
76  if (j == k)
77  continue;
78  crosscorr += rterm[j] * sterm[j] * m_re_sample.crossCorrSpectralFun(q, j, k)
79  * std::conj(rterm[k]) * std::conj(sterm[k]);
80  }
81  }
82  }
83  //! @TODO clarify complex vs double
84  ele.addIntensity((autocorr + crosscorr.real()) * M_PI / 4. / wavelength / wavelength);
85 }
86 
87 complex_t RoughMultiLayerContribution::get_refractive_term(size_t i_layer, double wavelength) const
88 {
89  return m_re_sample.avgeSlice(i_layer).material().refractiveIndex2(wavelength)
90  - m_re_sample.avgeSlice(i_layer + 1).material().refractiveIndex2(wavelength);
91 }
92 
94  const DiffuseElement& ele) const
95 {
96  const auto* in_plus = dynamic_cast<const ScalarFlux*>(ele.fluxIn(i_layer));
97  const auto* out_plus = dynamic_cast<const ScalarFlux*>(ele.fluxOut(i_layer));
98  const auto* in_minus = dynamic_cast<const ScalarFlux*>(ele.fluxIn(i_layer + 1));
99  const auto* out_minus = dynamic_cast<const ScalarFlux*>(ele.fluxOut(i_layer + 1));
100  ASSERT(in_plus && out_plus && in_minus && out_minus);
101 
102  const complex_t kiz_plus = in_plus->getScalarKz();
103  const complex_t kfz_plus = out_plus->getScalarKz();
104  const complex_t qz1_plus = -kiz_plus - kfz_plus;
105  const complex_t qz2_plus = -kiz_plus + kfz_plus;
106  const complex_t qz3_plus = -qz2_plus;
107  const complex_t qz4_plus = -qz1_plus;
108 
109  const double thickness = m_re_sample.avgeSlice(i_layer).thicknessOr0();
110  const complex_t T_in_plus = in_plus->getScalarT() * exp_I(kiz_plus * thickness);
111  const complex_t R_in_plus = in_plus->getScalarR() * exp_I(-kiz_plus * thickness);
112  const complex_t T_out_plus = out_plus->getScalarT() * exp_I(kfz_plus * thickness);
113  const complex_t R_out_plus = out_plus->getScalarR() * exp_I(-kfz_plus * thickness);
114 
115  const complex_t kiz_minus = in_minus->getScalarKz();
116  const complex_t kfz_minus = out_minus->getScalarKz();
117  const complex_t qz1_minus = -kiz_minus - kfz_minus;
118  const complex_t qz2_minus = -kiz_minus + kfz_minus;
119  const complex_t qz3_minus = -qz2_minus;
120  const complex_t qz4_minus = -qz1_minus;
121 
122  const LayerRoughness* roughness = m_re_sample.averageSlices().bottomRoughness(i_layer);
123  const double sigma = roughness ? roughness->sigma() : 0.;
124  const complex_t term1 = T_in_plus * T_out_plus * h_plus(qz1_plus * sigma);
125  const complex_t term2 = T_in_plus * R_out_plus * h_plus(qz2_plus * sigma);
126  const complex_t term3 = R_in_plus * T_out_plus * h_plus(qz3_plus * sigma);
127  const complex_t term4 = R_in_plus * R_out_plus * h_plus(qz4_plus * sigma);
128  const complex_t term5 =
129  in_minus->getScalarT() * out_minus->getScalarT() * h_min(qz1_minus * sigma);
130  const complex_t term6 =
131  in_minus->getScalarT() * out_minus->getScalarR() * h_min(qz2_minus * sigma);
132  const complex_t term7 =
133  in_minus->getScalarR() * out_minus->getScalarT() * h_min(qz3_minus * sigma);
134  const complex_t term8 =
135  in_minus->getScalarR() * out_minus->getScalarR() * h_min(qz4_minus * sigma);
136 
137  return term1 + term2 + term3 + term4 + term5 + term6 + term7 + term8;
138 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines M_PI and some more mathematical constants.
#define M_PI
Definition: Constants.h:44
Defines class DiffuseElement.
Defines class LayerInterface.
Defines class LayerRoughness.
Defines class Layer.
Defines class MultiLayer.
Defines class reSample.
Defines class RoughMultiLayerContribution.
Defines class ScalarFlux.
Data stucture containing both input and output of a single detector cell.
double alphaMean() const
const IFlux * fluxIn(size_t i_layer) const
const IFlux * fluxOut(size_t i_layer) const
double wavelength() const
void addIntensity(double intensity)
A roughness of interface between two layers.
double spectralFunction(R3 kvec) const
Returns power spectral density of the surface roughness.
double sigma() const
Returns rms of roughness.
complex_t refractiveIndex2(double wavelength) const
Returns squared refractive index.
Definition: Material.cpp:53
double crossCorrLength() const
Returns cross correlation length of roughnesses between interfaces.
Definition: MultiLayer.h:69
void compute(DiffuseElement &ele) const
complex_t get_refractive_term(size_t i_layer, double wavelength) const
RoughMultiLayerContribution(const reSample &re_sample)
complex_t get_sum8terms(size_t i_layer, const DiffuseElement &ele) const
Specular reflection and transmission coefficients in a layer in case of scalar interactions between t...
Definition: ScalarFlux.h:29
const LayerRoughness * bottomRoughness(size_t i_slice) const
Definition: SliceStack.cpp:75
double thicknessOr0() const
Definition: Slice.cpp:71
const Material & material() const
Definition: Slice.cpp:51
const LayerRoughness * topRoughness() const
Definition: Slice.cpp:76
Data structure that contains all the necessary data for scattering calculations.
Definition: ReSample.h:41
const Slice & avgeSlice(size_t i) const
Definition: ReSample.cpp:346
size_t numberOfSlices() const
Definition: ReSample.cpp:336
double crossCorrSpectralFun(R3 kvec, size_t j, size_t k) const
Fourier transform of the correlation function of roughnesses between the interfaces.
Definition: ReSample.cpp:398
const MultiLayer & sample() const
Definition: ReSample.h:58
const SliceStack & averageSlices() const
Definition: ReSample.cpp:341