BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
SumDWBA.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Resample/Coherence/SumDWBA.cpp
6 //! @brief Implements class SumDWBA.
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/Util/Assert.h"
22 
23 SumDWBA::SumDWBA(const IReParticle& ff, size_t i_layer)
24  : m_ff(ff.clone())
25  , m_i_layer(i_layer)
26 {
27 }
28 
30  : m_ff(ff.clone())
31  , m_i_layer()
32 {
33 }
34 
35 SumDWBA::~SumDWBA() = default;
36 
37 size_t SumDWBA::iLayer() const
38 {
39  ASSERT(m_i_layer.has_value());
40  return m_i_layer.value();
41 }
42 
43 complex_t SumDWBA::coherentFF(const DiffuseElement& ele) const
44 {
45  const WavevectorInfo& wavevectors = ele.wavevectorInfo();
46 
47  if (!m_i_layer.has_value())
48  // no slicing, pure Born approximation
49  return m_ff->theFF(wavevectors);
50 
51  const auto* inFlux = dynamic_cast<const ScalarFlux*>(ele.fluxIn(iLayer()));
52  const auto* outFlux = dynamic_cast<const ScalarFlux*>(ele.fluxOut(iLayer()));
53 
54  // Retrieve the two different incoming wavevectors in the layer
55  const C3& ki = wavevectors.getKi();
56  const complex_t kiz = inFlux->getScalarKz();
57  const C3 k_i_T{ki.x(), ki.y(), -kiz};
58  const C3 k_i_R{ki.x(), ki.y(), +kiz};
59 
60  // Retrieve the two different outgoing wavevector bins in the layer
61  const C3& kf = wavevectors.getKf();
62  const complex_t kfz = outFlux->getScalarKz();
63  const C3 k_f_T{kf.x(), kf.y(), +kfz};
64  const C3 k_f_R{kf.x(), kf.y(), -kfz};
65 
66  // Construct the four different scattering contributions wavevector infos
67  const double wavelength = wavevectors.vacuumLambda();
68  const WavevectorInfo q_TT(k_i_T, k_f_T, wavelength);
69  const WavevectorInfo q_RT(k_i_R, k_f_T, wavelength);
70  const WavevectorInfo q_TR(k_i_T, k_f_R, wavelength);
71  const WavevectorInfo q_RR(k_i_R, k_f_R, wavelength);
72 
73  // Get the four R,T coefficients
74  const complex_t T_in = inFlux->getScalarT();
75  const complex_t R_in = inFlux->getScalarR();
76  const complex_t T_out = outFlux->getScalarT();
77  const complex_t R_out = outFlux->getScalarR();
78 
79  // The four different scattering contributions;
80  // S stands for scattering off the particle,
81  // R for reflection off the layer interface.
82 
83  // Note that the order of multiplication matters:
84  // If a prefactor is 0, then theFF() won't be called.
85 
86  const complex_t term_S = T_in * T_out * m_ff->theFF(q_TT);
87  const complex_t term_RS = R_in * T_out * m_ff->theFF(q_RT);
88  const complex_t term_SR = T_in * R_out * m_ff->theFF(q_TR);
89  const complex_t term_RSR = R_in * R_out * m_ff->theFF(q_RR);
90 
91  return term_S + term_RS + term_SR + term_RSR;
92 }
93 
95 {
96  const WavevectorInfo& wavevectors = ele.wavevectorInfo();
97 
98  if (!m_i_layer.has_value()) {
99  // no slicing, pure Born approximation
100  SpinMatrix o = m_ff->thePolFF(wavevectors);
101  return {-o.c, +o.a, -o.d, +o.b};
102  }
103 
104  const auto* inFlux = dynamic_cast<const MatrixFlux*>(ele.fluxIn(iLayer()));
105  const auto* outFlux = dynamic_cast<const MatrixFlux*>(ele.fluxOut(iLayer()));
106 
107  // the required wavevectors inside the layer for
108  // different eigenmodes and in- and outgoing wavevector;
109  const complex_t kix = wavevectors.getKi().x();
110  const complex_t kiy = wavevectors.getKi().y();
111  const Spinor& kiz = inFlux->getKz();
112  const C3 ki_1R{kix, kiy, +kiz.u};
113  const C3 ki_1T{kix, kiy, -kiz.u};
114  const C3 ki_2R{kix, kiy, +kiz.v};
115  const C3 ki_2T{kix, kiy, -kiz.v};
116 
117  const complex_t kfx = wavevectors.getKf().x();
118  const complex_t kfy = wavevectors.getKf().y();
119  const Spinor& kfz = outFlux->getKz();
120  const C3 kf_1R{kfx, kfy, -kfz.u};
121  const C3 kf_1T{kfx, kfy, +kfz.u};
122  const C3 kf_2R{kfx, kfy, -kfz.v};
123  const C3 kf_2T{kfx, kfy, +kfz.v};
124 
125  // now each of the 16 matrix terms of the polarized DWBA is calculated:
126  // NOTE: when the underlying reflection/transmission coefficients are
127  // scalar, the eigenmodes have identical eigenvalues and spin polarization
128  // is used as a basis; in this case however the matrices get mixed:
129  // real m_M11 = calculated m_M12
130  // real m_M12 = calculated m_M11
131  // real m_M21 = calculated m_M22
132  // real m_M22 = calculated m_M21
133  // since both eigenvalues are identical, this does not influence the result.
134  SpinMatrix ff_BA; // will be overwritten
135 
136  double wavelength = wavevectors.vacuumLambda();
137 
138  // The following matrices each contain the four polarization conditions
139  // (p->p, p->m, m->p, m->m)
140  // The first two indices indicate a scattering from the 1/2 eigenstate into
141  // the 1/2 eigenstate, while the capital indices indicate a reflection
142  // before and/or after the scattering event (first index is in-state,
143  // second is out-state; this also applies to the internal matrix indices)
144 
145  // eigenmode 1 -> eigenmode 1: direct scattering
146  ff_BA = m_ff->thePolFF({ki_1T, kf_1T, wavelength});
147  SpinMatrix M11_S(-DotProduct(outFlux->T1min(), ff_BA * inFlux->T1plus()),
148  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->T1plus()),
149  -DotProduct(outFlux->T1min(), ff_BA * inFlux->T1min()),
150  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->T1min()));
151  // eigenmode 1 -> eigenmode 1: reflection and then scattering
152  ff_BA = m_ff->thePolFF({ki_1R, kf_1T, wavelength});
153  SpinMatrix M11_RS(-DotProduct(outFlux->T1min(), ff_BA * inFlux->R1plus()),
154  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->R1plus()),
155  -DotProduct(outFlux->T1min(), ff_BA * inFlux->R1min()),
156  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->R1min()));
157  // eigenmode 1 -> eigenmode 1: scattering and then reflection
158  ff_BA = m_ff->thePolFF({ki_1T, kf_1R, wavelength});
159  SpinMatrix M11_SR(-DotProduct(outFlux->R1min(), ff_BA * inFlux->T1plus()),
160  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->T1plus()),
161  -DotProduct(outFlux->R1min(), ff_BA * inFlux->T1min()),
162  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->T1min()));
163  // eigenmode 1 -> eigenmode 1: reflection, scattering and again reflection
164  ff_BA = m_ff->thePolFF({ki_1R, kf_1R, wavelength});
165  SpinMatrix M11_RSR(-DotProduct(outFlux->R1min(), ff_BA * inFlux->R1plus()),
166  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->R1plus()),
167  -DotProduct(outFlux->R1min(), ff_BA * inFlux->R1min()),
168  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->R1min()));
169 
170  // eigenmode 1 -> eigenmode 2: direct scattering
171  ff_BA = m_ff->thePolFF({ki_1T, kf_2T, wavelength});
172  SpinMatrix M12_S(-DotProduct(outFlux->T2min(), ff_BA * inFlux->T1plus()),
173  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->T1plus()),
174  -DotProduct(outFlux->T2min(), ff_BA * inFlux->T1min()),
175  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->T1min()));
176  // eigenmode 1 -> eigenmode 2: reflection and then scattering
177  ff_BA = m_ff->thePolFF({ki_1R, kf_2T, wavelength});
178  SpinMatrix M12_RS(-DotProduct(outFlux->T2min(), ff_BA * inFlux->R1plus()),
179  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->R1plus()),
180  -DotProduct(outFlux->T2min(), ff_BA * inFlux->R1min()),
181  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->R1min()));
182  // eigenmode 1 -> eigenmode 2: scattering and then reflection
183  ff_BA = m_ff->thePolFF({ki_1T, kf_2R, wavelength});
184  SpinMatrix M12_SR(-DotProduct(outFlux->R2min(), ff_BA * inFlux->T1plus()),
185  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->T1plus()),
186  -DotProduct(outFlux->R2min(), ff_BA * inFlux->T1min()),
187  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->T1min()));
188  // eigenmode 1 -> eigenmode 2: reflection, scattering and again reflection
189  ff_BA = m_ff->thePolFF({ki_1R, kf_2R, wavelength});
190  SpinMatrix M12_RSR(-DotProduct(outFlux->R2min(), ff_BA * inFlux->R1plus()),
191  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->R1plus()),
192  -DotProduct(outFlux->R2min(), ff_BA * inFlux->R1min()),
193  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->R1min()));
194 
195  // eigenmode 2 -> eigenmode 1: direct scattering
196  ff_BA = m_ff->thePolFF({ki_2T, kf_1T, wavelength});
197  SpinMatrix M21_S(-DotProduct(outFlux->T1min(), ff_BA * inFlux->T2plus()),
198  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->T2plus()),
199  -DotProduct(outFlux->T1min(), ff_BA * inFlux->T2min()),
200  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->T2min()));
201  // eigenmode 2 -> eigenmode 1: reflection and then scattering
202  ff_BA = m_ff->thePolFF({ki_2R, kf_1T, wavelength});
203  SpinMatrix M21_RS(-DotProduct(outFlux->T1min(), ff_BA * inFlux->R2plus()),
204  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->R2plus()),
205  -DotProduct(outFlux->T1min(), ff_BA * inFlux->R2min()),
206  +DotProduct(outFlux->T1plus(), ff_BA * inFlux->R2min()));
207  // eigenmode 2 -> eigenmode 1: scattering and then reflection
208  ff_BA = m_ff->thePolFF({ki_2T, kf_1R, wavelength});
209  SpinMatrix M21_SR(-DotProduct(outFlux->R1min(), ff_BA * inFlux->T2plus()),
210  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->T2plus()),
211  -DotProduct(outFlux->R1min(), ff_BA * inFlux->T2min()),
212  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->T2min()));
213  // eigenmode 2 -> eigenmode 1: reflection, scattering and again reflection
214  ff_BA = m_ff->thePolFF({ki_2R, kf_1R, wavelength});
215  SpinMatrix M21_RSR(-DotProduct(outFlux->R1min(), ff_BA * inFlux->R2plus()),
216  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->R2plus()),
217  -DotProduct(outFlux->R1min(), ff_BA * inFlux->R2min()),
218  +DotProduct(outFlux->R1plus(), ff_BA * inFlux->R2min()));
219 
220  // eigenmode 2 -> eigenmode 2: direct scattering
221  ff_BA = m_ff->thePolFF({ki_2T, kf_2T, wavelength});
222  SpinMatrix M22_S(-DotProduct(outFlux->T2min(), ff_BA * inFlux->T2plus()),
223  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->T2plus()),
224  -DotProduct(outFlux->T2min(), ff_BA * inFlux->T2min()),
225  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->T2min()));
226  // eigenmode 2 -> eigenmode 2: reflection and then scattering
227  ff_BA = m_ff->thePolFF({ki_2R, kf_2T, wavelength});
228  SpinMatrix M22_RS(-DotProduct(outFlux->T2min(), ff_BA * inFlux->R2plus()),
229  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->R2plus()),
230  -DotProduct(outFlux->T2min(), ff_BA * inFlux->R2min()),
231  +DotProduct(outFlux->T2plus(), ff_BA * inFlux->R2min()));
232  // eigenmode 2 -> eigenmode 2: scattering and then reflection
233  ff_BA = m_ff->thePolFF({ki_2T, kf_2R, wavelength});
234  SpinMatrix M22_SR(-DotProduct(outFlux->R2min(), ff_BA * inFlux->T2plus()),
235  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->T2plus()),
236  -DotProduct(outFlux->R2min(), ff_BA * inFlux->T2min()),
237  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->T2min()));
238  // eigenmode 2 -> eigenmode 2: reflection, scattering and again reflection
239  ff_BA = m_ff->thePolFF({ki_2R, kf_2R, wavelength});
240  SpinMatrix M22_RSR(-DotProduct(outFlux->R2min(), ff_BA * inFlux->R2plus()),
241  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->R2plus()),
242  -DotProduct(outFlux->R2min(), ff_BA * inFlux->R2min()),
243  +DotProduct(outFlux->R2plus(), ff_BA * inFlux->R2min()));
244 
245  return M11_S + M11_RS + M11_SR + M11_RSR + M12_S + M12_RS + M12_SR + M12_RSR + M21_S + M21_RS
246  + M21_SR + M21_RSR + M22_S + M22_RS + M22_SR + M22_RSR;
247 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines class DiffuseElement.
Defines and implements interface IReParticle.
Defines class MatrixFlux.
Defines class ScalarFlux.
complex_t DotProduct(const Spinor &r, const Spinor &t)
Definition: Spinor.cpp:55
Defines class SumDWBA.
Defines WavevectorInfo.
Data stucture containing both input and output of a single detector cell.
const IFlux * fluxIn(size_t i_layer) const
const IFlux * fluxOut(size_t i_layer) const
WavevectorInfo wavevectorInfo() const
Abstract base class for reprocessed particles.
Definition: IReParticle.h:37
Specular reflection and transmission coefficients in a layer in case of magnetic interactions between...
Definition: MatrixFlux.h:32
Specular reflection and transmission coefficients in a layer in case of scalar interactions between t...
Definition: ScalarFlux.h:29
complex_t a
Definition: SpinMatrix.h:68
complex_t b
Definition: SpinMatrix.h:68
complex_t c
Definition: SpinMatrix.h:68
complex_t d
Definition: SpinMatrix.h:68
Definition: Spinor.h:20
complex_t v
Definition: Spinor.h:31
complex_t u
Definition: Spinor.h:31
const std::optional< size_t > m_i_layer
Definition: SumDWBA.h:55
SpinMatrix coherentPolFF(const DiffuseElement &ele) const
Returns the coherent sum of the four DWBA terms for polarized scattering.
Definition: SumDWBA.cpp:94
SumDWBA(const IReParticle &ff, size_t i_layer)
Definition: SumDWBA.cpp:23
virtual ~SumDWBA()
const std::unique_ptr< const IReParticle > m_ff
Definition: SumDWBA.h:54
complex_t coherentFF(const DiffuseElement &ele) const
Returns the coherent sum of the four DWBA terms for scalar scattering.
Definition: SumDWBA.cpp:43
size_t iLayer() const
Definition: SumDWBA.cpp:37
Holds all wavevector information relevant for calculating form factors.
C3 getKi() const
C3 getKf() const
double vacuumLambda() const