BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularMagneticStrategy_v2 Class Reference

Implements the magnetic Fresnel computation without roughness. More...

Inheritance diagram for SpecularMagneticStrategy_v2:
[legend]
Collaboration diagram for SpecularMagneticStrategy_v2:
[legend]

Public Types

using coefficient_pointer_type = std::unique_ptr< const coefficient_type >
 
using coefficient_type = MatrixRTCoefficients_v2
 
using coeffs_t = std::vector< coefficient_pointer_type >
 

Public Member Functions

virtual std::variant< complex_t, Eigen::Matrix2cd > computeTopLayerR (const std::vector< Slice > &slices, const std::vector< complex_t > &kz) const override
 
ISpecularStrategy::coeffs_t Execute (const std::vector< Slice > &slices, const kvector_t &k) const
 Computes refraction angle reflection/transmission coefficients for given sliced multilayer and wavevector k. More...
 
ISpecularStrategy::coeffs_t Execute (const std::vector< Slice > &slices, const std::vector< complex_t > &kz) const
 Computes refraction angle reflection/transmission coefficients for given sliced multilayer and a set of kz projections corresponding to each slice. More...
 

Static Private Member Functions

static void calculateTR (MatrixRTCoefficients_v2 &coeff)
 Computes frobenius matrices for multilayer solution. More...
 
static void calculateZeroFieldTR (MatrixRTCoefficients_v2 &coeff)
 
static std::vector< MatrixRTCoefficients_v2computeTR (const std::vector< Slice > &slices, const std::vector< complex_t > &kzs)
 
static std::pair< Eigen::Matrix2cd, complex_tfindNormalizationCoefficients (const MatrixRTCoefficients_v2 &coeff)
 finds linear coefficients for normalizing transmitted wave to unity. More...
 
static void nullifyBottomReflection (MatrixRTCoefficients_v2 &coeff)
 initializes reflectionless bottom boundary condition. More...
 
static void propagateBackwardsForwards (std::vector< MatrixRTCoefficients_v2 > &coeff, const std::vector< Slice > &slices)
 Propagates boundary conditions from the bottom to the top of the layer stack. More...
 
static void setNoTransmission (MatrixRTCoefficients_v2 &coeff)
 

Detailed Description

Implements the magnetic Fresnel computation without roughness.

Implements the matrix formalism for the calculation of wave amplitudes of the coherent wave solution in a multilayer with magnetization. For a detailed description see internal document "Polarized Specular Reflectometry"

Definition at line 37 of file SpecularMagneticStrategy_v2.h.

Member Typedef Documentation

◆ coefficient_pointer_type

◆ coefficient_type

◆ coeffs_t

Member Function Documentation

◆ calculateTR()

void SpecularMagneticStrategy_v2::calculateTR ( MatrixRTCoefficients_v2 coeff)
staticprivate

Computes frobenius matrices for multilayer solution.

Definition at line 94 of file SpecularMagneticStrategy_v2.cpp.

95 {
96  const double b = coeff.m_b.mag();
97  if (b == 0.0) {
98  calculateZeroFieldTR(coeff);
99  return;
100  }
101 
102  const double bpbz = b + coeff.m_b.z();
103  const double bmbz = b - coeff.m_b.z();
104  const complex_t bxmby = coeff.m_b.x() - I * coeff.m_b.y();
105  const complex_t bxpby = coeff.m_b.x() + I * coeff.m_b.y();
106  const complex_t l_1 = coeff.m_lambda(0);
107  const complex_t l_2 = coeff.m_lambda(1);
108 
109  auto& T1 = coeff.T1;
110  T1 << bmbz, -bxmby, -bmbz * l_1, bxmby * l_1, -bxpby, bpbz, bxpby * l_1, -bpbz * l_1,
111  -bmbz / l_1, bxmby / l_1, bmbz, -bxmby, bxpby / l_1, -bpbz / l_1, -bxpby, bpbz;
112  T1 /= 4.0 * b;
113 
114  auto& R1 = coeff.R1;
115  R1 << T1(0, 0), T1(0, 1), -T1(0, 2), -T1(0, 3), T1(1, 0), T1(1, 1), -T1(1, 2), -T1(1, 3),
116  -T1(2, 0), -T1(2, 1), T1(2, 2), T1(2, 3), -T1(3, 0), -T1(3, 1), T1(3, 2), T1(3, 3);
117 
118  auto& T2 = coeff.T2;
119  T2 << bpbz, bxmby, -bpbz * l_2, -bxmby * l_2, bxpby, bmbz, -bxpby * l_2, -bmbz * l_2,
120  -bpbz / l_2, -bxmby / l_2, bpbz, bxmby, -bxpby / l_2, -bmbz / l_2, bxpby, bmbz;
121  T2 /= 4.0 * b;
122 
123  auto& R2 = coeff.R2;
124  R2 << T2(0, 0), T2(0, 1), -T2(0, 2), -T2(0, 3), T2(1, 0), T2(1, 1), -T2(1, 2), -T2(1, 3),
125  -T2(2, 0), -T2(2, 1), T2(2, 2), T2(2, 3), -T2(3, 0), -T2(3, 1), T2(3, 2), T2(3, 3);
126 }
constexpr complex_t I
Definition: Complex.h:21
std::complex< double > complex_t
Definition: Complex.h:20
double mag() const
Returns magnitude of the vector.
T z() const
Returns z-component in cartesian coordinate system.
Definition: BasicVector3D.h:67
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
Eigen::Vector2cd m_lambda
wave propagation direction (-1 for direct one, 1 for time reverse)
Eigen::Matrix4cd T2
matrix selecting the transmitted part of the second eigenmode
Eigen::Matrix4cd R1
matrix selecting the reflected part of the first eigenmode
Eigen::Matrix4cd T1
matrix selecting the transmitted part of the first eigenmode
kvector_t m_b
normalized magnetic field impact (with correction for external mag. field)
Eigen::Matrix4cd R2
matrix selecting the reflected part of the second eigenmode
static void calculateZeroFieldTR(MatrixRTCoefficients_v2 &coeff)

References calculateZeroFieldTR(), I, MatrixRTCoefficients_v2::m_b, MatrixRTCoefficients_v2::m_lambda, BasicVector3D< T >::mag(), MatrixRTCoefficients_v2::R1, MatrixRTCoefficients_v2::R2, MatrixRTCoefficients_v2::T1, MatrixRTCoefficients_v2::T2, BasicVector3D< T >::x(), BasicVector3D< T >::y(), and BasicVector3D< T >::z().

Here is the call graph for this function:

◆ calculateZeroFieldTR()

void SpecularMagneticStrategy_v2::calculateZeroFieldTR ( MatrixRTCoefficients_v2 coeff)
staticprivate

Definition at line 128 of file SpecularMagneticStrategy_v2.cpp.

129 {
130  coeff.T1 = Eigen::Matrix4cd::Zero();
131  coeff.R1 = Eigen::Matrix4cd::Zero();
132  coeff.T2 = Eigen::Matrix4cd::Zero();
133  coeff.R2 = Eigen::Matrix4cd::Zero();
134 
135  // lambda_1 == lambda_2, no difference which one to use
136  const complex_t eigen_value = coeff.m_lambda(0);
137 
138  Eigen::Matrix3cd Tblock;
139  Tblock << 0.5, 0.0, -0.5 * eigen_value, 0.0, 0.0, 0.0, -0.5 / eigen_value, 0.0, 0.5;
140 
141  Eigen::Matrix3cd Rblock;
142  Rblock << 0.5, 0.0, 0.5 * eigen_value, 0.0, 0.0, 0.0, 0.5 / eigen_value, 0.0, 0.5;
143 
144  coeff.T1.block<3, 3>(1, 1) = Tblock;
145  coeff.R1.block<3, 3>(1, 1) = Rblock;
146  coeff.T2.block<3, 3>(0, 0) = Tblock;
147  coeff.R2.block<3, 3>(0, 0) = Rblock;
148 }

References MatrixRTCoefficients_v2::m_lambda, MatrixRTCoefficients_v2::R1, MatrixRTCoefficients_v2::R2, MatrixRTCoefficients_v2::T1, and MatrixRTCoefficients_v2::T2.

Referenced by calculateTR().

◆ computeTopLayerR()

std::variant< complex_t, Eigen::Matrix2cd > SpecularMagneticStrategy_v2::computeTopLayerR ( const std::vector< Slice > &  slices,
const std::vector< complex_t > &  kz 
) const
overridevirtual

Implements ISpecularStrategy.

Definition at line 52 of file SpecularMagneticStrategy_v2.cpp.

54 {
55  throw std::runtime_error("Not implemented");
56 }

◆ computeTR()

std::vector< MatrixRTCoefficients_v2 > SpecularMagneticStrategy_v2::computeTR ( const std::vector< Slice > &  slices,
const std::vector< complex_t > &  kzs 
)
staticprivate

Definition at line 59 of file SpecularMagneticStrategy_v2.cpp.

61 {
62  if (kzs[0] == 0.)
63  throw std::runtime_error("Edge case k_z = 0 not implemented");
64 
65  if (slices.size() != kzs.size())
66  throw std::runtime_error(
67  "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
68  if (slices.empty())
69  return {};
70 
71  std::vector<MatrixRTCoefficients_v2> result;
72  result.reserve(slices.size());
73 
74  const double kz_sign = kzs.front().real() > 0.0 ? 1.0 : -1.0; // save sign to restore it later
75  const kvector_t b_0 = magneticImpact(slices.front().bField());
76  result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0});
77  for (size_t i = 1, size = slices.size(); i < size; ++i) {
78  kvector_t b = magneticImpact(slices[i].bField()) - b_0;
79  result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], b.mag())), b);
80  }
81 
82  if (result.front().m_lambda == Eigen::Vector2cd::Zero()) {
83  std::for_each(result.begin(), result.end(), [](auto& coeff) { setNoTransmission(coeff); });
84  return result;
85  }
86 
87  std::for_each(result.begin(), result.end(), [](auto& coeff) { calculateTR(coeff); });
88  nullifyBottomReflection(result.back());
89  propagateBackwardsForwards(result, slices);
90 
91  return result;
92 }
static void propagateBackwardsForwards(std::vector< MatrixRTCoefficients_v2 > &coeff, const std::vector< Slice > &slices)
Propagates boundary conditions from the bottom to the top of the layer stack.
static void nullifyBottomReflection(MatrixRTCoefficients_v2 &coeff)
initializes reflectionless bottom boundary condition.

References BasicVector3D< T >::mag(), nullifyBottomReflection(), and propagateBackwardsForwards().

Referenced by Execute().

Here is the call graph for this function:

◆ Execute() [1/2]

ISpecularStrategy::coeffs_t SpecularMagneticStrategy_v2::Execute ( const std::vector< Slice > &  slices,
const kvector_t k 
) const
virtual

Computes refraction angle reflection/transmission coefficients for given sliced multilayer and wavevector k.

Implements ISpecularStrategy.

Definition at line 31 of file SpecularMagneticStrategy_v2.cpp.

33 {
34  return Execute(slices, KzComputation::computeReducedKz(slices, k));
35 }
ISpecularStrategy::coeffs_t Execute(const std::vector< Slice > &slices, const kvector_t &k) const
Computes refraction angle reflection/transmission coefficients for given sliced multilayer and waveve...
std::vector< complex_t > computeReducedKz(const std::vector< Slice > &slices, kvector_t k)

References KzComputation::computeReducedKz().

Here is the call graph for this function:

◆ Execute() [2/2]

ISpecularStrategy::coeffs_t SpecularMagneticStrategy_v2::Execute ( const std::vector< Slice > &  slices,
const std::vector< complex_t > &  kz 
) const
virtual

Computes refraction angle reflection/transmission coefficients for given sliced multilayer and a set of kz projections corresponding to each slice.

Implements ISpecularStrategy.

Definition at line 38 of file SpecularMagneticStrategy_v2.cpp.

40 {
41  if (slices.size() != kz.size())
42  throw std::runtime_error("Number of slices does not match the size of the kz-vector");
43 
45  for (auto& coeff : computeTR(slices, kz))
46  result.push_back(std::make_unique<MatrixRTCoefficients_v2>(coeff));
47 
48  return result;
49 }
std::vector< std::unique_ptr< const ILayerRTCoefficients > > coeffs_t
static std::vector< MatrixRTCoefficients_v2 > computeTR(const std::vector< Slice > &slices, const std::vector< complex_t > &kzs)

References computeTR().

Here is the call graph for this function:

◆ findNormalizationCoefficients()

std::pair< Eigen::Matrix2cd, complex_t > SpecularMagneticStrategy_v2::findNormalizationCoefficients ( const MatrixRTCoefficients_v2 coeff)
staticprivate

finds linear coefficients for normalizing transmitted wave to unity.

The left column of the returned matrix corresponds to the coefficients for pure spin-up wave, while the right column - to the coefficients for the spin-down one.

Definition at line 252 of file SpecularMagneticStrategy_v2.cpp.

253 {
254  const Eigen::Vector2cd Ta = coeff.T1plus() + coeff.T2plus();
255  const Eigen::Vector2cd Tb = coeff.T1min() + coeff.T2min();
256 
257  Eigen::Matrix2cd S;
258  S << Ta(0), Tb(0), Ta(1), Tb(1);
259 
260  Eigen::Matrix2cd SInverse;
261  SInverse << S(1, 1), -S(0, 1), -S(1, 0), S(0, 0);
262  const complex_t d1 = S(1, 1) - S(0, 1);
263  const complex_t d2 = S(1, 0) - S(0, 0);
264  const complex_t denominator = S(0, 0) * d1 - d2 * S(0, 1);
265 
266  return {SInverse, denominator};
267 }
Eigen::Vector2cd T2plus() const override
Eigen::Vector2cd T2min() const override
Eigen::Vector2cd T1plus() const override
The following functions return the transmitted and reflected amplitudes for different incoming beam p...
Eigen::Vector2cd T1min() const override

References MatrixRTCoefficients_v2::T1min(), MatrixRTCoefficients_v2::T1plus(), MatrixRTCoefficients_v2::T2min(), and MatrixRTCoefficients_v2::T2plus().

Referenced by propagateBackwardsForwards().

Here is the call graph for this function:

◆ nullifyBottomReflection()

void SpecularMagneticStrategy_v2::nullifyBottomReflection ( MatrixRTCoefficients_v2 coeff)
staticprivate

initializes reflectionless bottom boundary condition.

Definition at line 160 of file SpecularMagneticStrategy_v2.cpp.

161 {
162  const complex_t l_1 = coeff.m_lambda(0);
163  const complex_t l_2 = coeff.m_lambda(1);
164  const double b_mag = coeff.m_b.mag();
165  const kvector_t& b = coeff.m_b;
166 
167  if (b_mag == 0.0) {
168  // both eigenvalues are the same, no difference which one to take
169  coeff.m_w_plus << -l_1, 0.0, 1.0, 0.0;
170  coeff.m_w_min << 0.0, -l_1, 0.0, 1.0;
171  return;
172  }
173 
174  // First basis vector that has no upward going wave amplitude
175  coeff.m_w_min(0) = (b.x() - I * b.y()) * (l_1 - l_2) / 2.0 / b_mag;
176  coeff.m_w_min(1) = b.z() * (l_2 - l_1) / 2.0 / b_mag - (l_1 + l_2) / 2.0;
177  coeff.m_w_min(2) = 0.0;
178  coeff.m_w_min(3) = 1.0;
179 
180  // Second basis vector that has no upward going wave amplitude
181  coeff.m_w_plus(0) = -(l_1 + l_2) / 2.0 - b.z() / (l_1 + l_2);
182  coeff.m_w_plus(1) = (b.x() + I * b.y()) * (l_1 - l_2) / 2.0 / b_mag;
183  coeff.m_w_plus(2) = 1.0;
184  coeff.m_w_plus(3) = 0.0;
185 }
Eigen::Vector4cd m_w_plus
boundary values for up-polarization
Eigen::Vector4cd m_w_min
boundary values for down-polarization

References I, MatrixRTCoefficients_v2::m_b, MatrixRTCoefficients_v2::m_lambda, MatrixRTCoefficients_v2::m_w_min, MatrixRTCoefficients_v2::m_w_plus, BasicVector3D< T >::mag(), BasicVector3D< T >::x(), BasicVector3D< T >::y(), and BasicVector3D< T >::z().

Referenced by computeTR().

Here is the call graph for this function:

◆ propagateBackwardsForwards()

void SpecularMagneticStrategy_v2::propagateBackwardsForwards ( std::vector< MatrixRTCoefficients_v2 > &  coeff,
const std::vector< Slice > &  slices 
)
staticprivate

Propagates boundary conditions from the bottom to the top of the layer stack.

Used to compute boundary conditions from the bottom one (with nullified reflection) simultaneously propagates amplitudes forward again Due to the use of temporary objects this is combined into one function now

Definition at line 187 of file SpecularMagneticStrategy_v2.cpp.

189 {
190  const int size = static_cast<int>(coeff.size());
191  std::vector<Eigen::Matrix2cd> SMatrices(coeff.size());
192  std::vector<complex_t> Normalization(coeff.size());
193 
194  for (int index = size - 2; index >= 0; --index) {
195  const size_t i = static_cast<size_t>(index);
196  const double t = slices[i].thickness();
197  const auto kz = coeff[i].getKz();
198  const Eigen::Matrix4cd l = coeff[i].R1 * GetImExponential(kz(0) * t)
199  + coeff[i].T1 * GetImExponential(-kz(0) * t)
200  + coeff[i].R2 * GetImExponential(kz(1) * t)
201  + coeff[i].T2 * GetImExponential(-kz(1) * t);
202  coeff[i].m_w_plus = l * coeff[i + 1].m_w_plus;
203  coeff[i].m_w_min = l * coeff[i + 1].m_w_min;
204 
205  // rotate and normalize polarization
206  const auto Snorm = findNormalizationCoefficients(coeff[i]);
207  auto S = Snorm.first;
208  auto norm = Snorm.second;
209 
210  SMatrices[i] = S;
211  Normalization[i] = norm;
212 
213  const complex_t a_plus = S(0, 0) / norm;
214  const complex_t b_plus = S(1, 0) / norm;
215  const complex_t a_min = S(0, 1) / norm;
216  const complex_t b_min = S(1, 1) / norm;
217 
218  const Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min;
219  const Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min;
220 
221  coeff[i].m_w_plus = std::move(w_plus);
222  coeff[i].m_w_min = std::move(w_min);
223  }
224 
225  complex_t dumpingFactor = 1;
226  Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity();
227  for (size_t i = 1; i < coeff.size(); ++i) {
228  dumpingFactor = dumpingFactor * Normalization[i - 1];
229  S = SMatrices[i - 1] * S;
230 
231  if (std::isinf(std::norm(dumpingFactor))) {
232  // not entirely sure, whether this is the correct edge case
233  std::for_each(coeff.begin() + i, coeff.end(),
234  [](auto& coeff) { setNoTransmission(coeff); });
235  break;
236  }
237 
238  const complex_t a_plus = S(0, 0) / dumpingFactor;
239  const complex_t b_plus = S(1, 0) / dumpingFactor;
240  const complex_t a_min = S(0, 1) / dumpingFactor;
241  const complex_t b_min = S(1, 1) / dumpingFactor;
242 
243  Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min;
244  Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min;
245 
246  coeff[i].m_w_plus = std::move(w_plus);
247  coeff[i].m_w_min = std::move(w_min);
248  }
249 }
static std::pair< Eigen::Matrix2cd, complex_t > findNormalizationCoefficients(const MatrixRTCoefficients_v2 &coeff)
finds linear coefficients for normalizing transmitted wave to unity.

References findNormalizationCoefficients().

Referenced by computeTR().

Here is the call graph for this function:

◆ setNoTransmission()

void SpecularMagneticStrategy_v2::setNoTransmission ( MatrixRTCoefficients_v2 coeff)
staticprivate

Definition at line 150 of file SpecularMagneticStrategy_v2.cpp.

151 {
152  coeff.m_w_plus = Eigen::Vector4cd::Zero();
153  coeff.m_w_min = Eigen::Vector4cd::Zero();
154  coeff.T1 = Eigen::Matrix4cd::Identity() / 4.0;
155  coeff.R1 = coeff.T1;
156  coeff.T2 = coeff.T1;
157  coeff.R2 = coeff.T1;
158 }

References MatrixRTCoefficients_v2::m_w_min, MatrixRTCoefficients_v2::m_w_plus, MatrixRTCoefficients_v2::R1, MatrixRTCoefficients_v2::R2, MatrixRTCoefficients_v2::T1, and MatrixRTCoefficients_v2::T2.


The documentation for this class was generated from the following files: