BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularMagneticStrategy Class Reference
Inheritance diagram for SpecularMagneticStrategy:
Collaboration diagram for SpecularMagneticStrategy:

Public Types

using coeffs_t = std::vector< std::unique_ptr< const ILayerRTCoefficients > >
 

Public Member Functions

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

Static Private Member Functions

static std::vector< MatrixRTCoefficients_v2computeTR (const std::vector< Slice > &slices, const std::vector< complex_t > &kzs)
 
static void calculateTR (MatrixRTCoefficients_v2 &coeff)
 
static void calculateZeroFieldTR (MatrixRTCoefficients_v2 &coeff)
 
static void setNoTransmission (MatrixRTCoefficients_v2 &coeff)
 
static void nullifyBottomReflection (MatrixRTCoefficients_v2 &coeff)
 
static void propagateBackwardsForwards (std::vector< MatrixRTCoefficients_v2 > &coeff, const std::vector< Slice > &slices)
 
static std::pair< Eigen::Matrix2cd, complex_tfindNormalizationCoefficients (const 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 32 of file SpecularMagneticStrategy.h.

Member Typedef Documentation

◆ coeffs_t

using ISpecularStrategy::coeffs_t = std::vector<std::unique_ptr<const ILayerRTCoefficients> >
inherited

Definition at line 40 of file ISpecularStrategy.h.

Member Function Documentation

◆ Execute() [1/2]

ISpecularStrategy::coeffs_t SpecularMagneticStrategy::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 32 of file SpecularMagneticStrategy.cpp.

34 {
35  return Execute(slices, KzComputation::computeReducedKz(slices, k));
36 }
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::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 39 of file SpecularMagneticStrategy.cpp.

41 {
42  if (slices.size() != kz.size())
43  throw std::runtime_error("Number of slices does not match the size of the kz-vector");
44 
46  for (auto& coeff : computeTR(slices, kz))
47  result.push_back(std::make_unique<MatrixRTCoefficients_v2>(coeff));
48 
49  return result;
50 }
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:

◆ computeTR()

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

Definition at line 53 of file SpecularMagneticStrategy.cpp.

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

References anonymous_namespace{SpecularMagneticStrategy.cpp}::checkForUnderflow(), anonymous_namespace{SpecularMagneticStrategy.cpp}::eigenvalues(), BasicVector3D< T >::mag(), anonymous_namespace{SpecularMagneticStrategy.cpp}::magneticImpact(), nullifyBottomReflection(), and propagateBackwardsForwards().

Referenced by Execute().

Here is the call graph for this function:

◆ calculateTR()

void SpecularMagneticStrategy::calculateTR ( MatrixRTCoefficients_v2 coeff)
staticprivate

Computes frobenius matrices for multilayer solution.

Definition at line 88 of file SpecularMagneticStrategy.cpp.

89 {
90  const double b = coeff.m_b.mag();
91  if (b == 0.0) {
92  calculateZeroFieldTR(coeff);
93  return;
94  }
95 
96  const double bpbz = b + coeff.m_b.z();
97  const double bmbz = b - coeff.m_b.z();
98  const complex_t bxmby = coeff.m_b.x() - I * coeff.m_b.y();
99  const complex_t bxpby = coeff.m_b.x() + I * coeff.m_b.y();
100  const complex_t l_1 = coeff.m_lambda(0);
101  const complex_t l_2 = coeff.m_lambda(1);
102 
103  auto& T1 = coeff.T1;
104  T1 << bmbz, -bxmby, -bmbz * l_1, bxmby * l_1, -bxpby, bpbz, bxpby * l_1, -bpbz * l_1,
105  -bmbz / l_1, bxmby / l_1, bmbz, -bxmby, bxpby / l_1, -bpbz / l_1, -bxpby, bpbz;
106  T1 /= 4.0 * b;
107 
108  auto& R1 = coeff.R1;
109  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),
110  -T1(2, 0), -T1(2, 1), T1(2, 2), T1(2, 3), -T1(3, 0), -T1(3, 1), T1(3, 2), T1(3, 3);
111 
112  auto& T2 = coeff.T2;
113  T2 << bpbz, bxmby, -bpbz * l_2, -bxmby * l_2, bxpby, bmbz, -bxpby * l_2, -bmbz * l_2,
114  -bpbz / l_2, -bxmby / l_2, bpbz, bxmby, -bxpby / l_2, -bmbz / l_2, bxpby, bmbz;
115  T2 /= 4.0 * b;
116 
117  auto& R2 = coeff.R2;
118  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),
119  -T2(2, 0), -T2(2, 1), T2(2, 2), T2(2, 3), -T2(3, 0), -T2(3, 1), T2(3, 2), T2(3, 3);
120 }
constexpr complex_t I
Definition: Complex.h:21
std::complex< double > complex_t
Definition: Complex.h:20
T z() const
Returns z-component in cartesian coordinate system.
Definition: BasicVector3D.h:68
T y() const
Returns y-component in cartesian coordinate system.
Definition: BasicVector3D.h:66
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:64
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::calculateZeroFieldTR ( MatrixRTCoefficients_v2 coeff)
staticprivate

Definition at line 122 of file SpecularMagneticStrategy.cpp.

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

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

Referenced by calculateTR().

◆ setNoTransmission()

void SpecularMagneticStrategy::setNoTransmission ( MatrixRTCoefficients_v2 coeff)
staticprivate

Definition at line 144 of file SpecularMagneticStrategy.cpp.

145 {
146  coeff.m_w_plus = Eigen::Vector4cd::Zero();
147  coeff.m_w_min = Eigen::Vector4cd::Zero();
148  coeff.T1 = Eigen::Matrix4cd::Identity() / 4.0;
149  coeff.R1 = coeff.T1;
150  coeff.T2 = coeff.T1;
151  coeff.R2 = coeff.T1;
152 }
Eigen::Vector4cd m_w_plus
boundary values for up-polarization
Eigen::Vector4cd m_w_min
boundary values for down-polarization

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

◆ nullifyBottomReflection()

void SpecularMagneticStrategy::nullifyBottomReflection ( MatrixRTCoefficients_v2 coeff)
staticprivate

initializes reflectionless bottom boundary condition.

Definition at line 154 of file SpecularMagneticStrategy.cpp.

155 {
156  const complex_t l_1 = coeff.m_lambda(0);
157  const complex_t l_2 = coeff.m_lambda(1);
158  const double b_mag = coeff.m_b.mag();
159  const kvector_t& b = coeff.m_b;
160 
161  if (b_mag == 0.0) {
162  // both eigenvalues are the same, no difference which one to take
163  coeff.m_w_plus << -l_1, 0.0, 1.0, 0.0;
164  coeff.m_w_min << 0.0, -l_1, 0.0, 1.0;
165  return;
166  }
167 
168  // First basis vector that has no upward going wave amplitude
169  coeff.m_w_min(0) = (b.x() - I * b.y()) * (l_1 - l_2) / 2.0 / b_mag;
170  coeff.m_w_min(1) = b.z() * (l_2 - l_1) / 2.0 / b_mag - (l_1 + l_2) / 2.0;
171  coeff.m_w_min(2) = 0.0;
172  coeff.m_w_min(3) = 1.0;
173 
174  // Second basis vector that has no upward going wave amplitude
175  coeff.m_w_plus(0) = -(l_1 + l_2) / 2.0 - b.z() / (l_1 + l_2);
176  coeff.m_w_plus(1) = (b.x() + I * b.y()) * (l_1 - l_2) / 2.0 / b_mag;
177  coeff.m_w_plus(2) = 1.0;
178  coeff.m_w_plus(3) = 0.0;
179 }

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::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 181 of file SpecularMagneticStrategy.cpp.

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

References findNormalizationCoefficients(), and anonymous_namespace{SpecularMagneticStrategy.cpp}::GetImExponential().

Referenced by computeTR().

Here is the call graph for this function:

◆ findNormalizationCoefficients()

std::pair< Eigen::Matrix2cd, complex_t > SpecularMagneticStrategy::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 246 of file SpecularMagneticStrategy.cpp.

247 {
248  const Eigen::Vector2cd Ta = coeff.T1plus() + coeff.T2plus();
249  const Eigen::Vector2cd Tb = coeff.T1min() + coeff.T2min();
250 
251  Eigen::Matrix2cd S;
252  S << Ta(0), Tb(0), Ta(1), Tb(1);
253 
254  Eigen::Matrix2cd SInverse;
255  SInverse << S(1, 1), -S(0, 1), -S(1, 0), S(0, 0);
256  const complex_t d1 = S(1, 1) - S(0, 1);
257  const complex_t d2 = S(1, 0) - S(0, 0);
258  const complex_t denominator = S(0, 0) * d1 - d2 * S(0, 1);
259 
260  return {SInverse, denominator};
261 }
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:

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