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

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
 

Private Member Functions

std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeRoughnessMatrices (const MatrixRTCoefficients_v3 &coeff_i, const MatrixRTCoefficients_v3 &coeff_i1, double sigma) const
 
virtual std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeBackwardsSubmatrices (const MatrixRTCoefficients_v3 &coeff_i, const MatrixRTCoefficients_v3 &coeff_i1, double sigma) const
 
std::vector< MatrixRTCoefficients_v3computeTR (const std::vector< Slice > &slices, const std::vector< complex_t > &kzs) const
 
void calculateUpwards (std::vector< MatrixRTCoefficients_v3 > &coeff, const std::vector< Slice > &slices) const
 

Detailed Description

Implements the magnetic Fresnel computation with Nevot-Croce roughness.

Implements the transfer matrix formalism for the calculation of wave amplitudes of the coherent wave solution in a multilayer with magnetization. For a description, see internal document "Polarized Implementation of the Transfer Matrix Method"

Definition at line 30 of file SpecularMagneticNewNCStrategy.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

◆ computeRoughnessMatrices()

std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > SpecularMagneticNewNCStrategy::computeRoughnessMatrices ( const MatrixRTCoefficients_v3 coeff_i,
const MatrixRTCoefficients_v3 coeff_i1,
double  sigma 
) const
private

Definition at line 23 of file SpecularMagneticNewNCStrategy.cpp.

26 {
27  complex_t beta_i = coeff_i.m_lambda(1) - coeff_i.m_lambda(0);
28  complex_t beta_i1 = coeff_i1.m_lambda(1) - coeff_i1.m_lambda(0);
29 
30  auto roughness_matrix = [sigma, &coeff_i, &coeff_i1, beta_i, beta_i1](double sign) {
31  const complex_t alpha_p = coeff_i1.m_lambda(0) + coeff_i1.m_lambda(1)
32  + sign * (coeff_i.m_lambda(0) + coeff_i.m_lambda(1));
33  auto b_p_vec = beta_i1 * coeff_i1.m_b + sign * beta_i * coeff_i.m_b;
34 
35  auto square = [](auto& v) { return v.x() * v.x() + v.y() * v.y() + v.z() * v.z(); };
36  complex_t beta_p = std::sqrt(checkForUnderflow(square(b_p_vec)));
37  b_p_vec /= beta_p;
38 
39  const complex_t alpha_pp = -(alpha_p * alpha_p + beta_p * beta_p) * sigma * sigma / 8.;
40  const complex_t beta_pp = -alpha_p * beta_p * sigma * sigma / 4.;
41 
42  Eigen::Matrix2cd QL, QR;
43 
44  const complex_t factor1 = std::sqrt(2. * (1. + b_p_vec.z()));
45  const complex_t factor2 = std::sqrt(2. * (1. - b_p_vec.z()));
46  QL << (b_p_vec.z() + 1.) / factor1, (b_p_vec.z() - 1.) / factor2,
47  (b_p_vec.x() + I * b_p_vec.y()) / factor1, (b_p_vec.x() + I * b_p_vec.y()) / factor2;
48  QR << (b_p_vec.z() + 1.) / factor1, (b_p_vec.x() - I * b_p_vec.y()) / factor1,
49  (b_p_vec.z() - 1.) / factor2, (b_p_vec.x() - I * b_p_vec.y()) / factor2;
50 
51  const Eigen::Matrix2cd exp1 =
52  Eigen::DiagonalMatrix<complex_t, 2>({std::exp(alpha_pp), std::exp(alpha_pp)});
53 
54  if (std::abs(beta_p) > std::numeric_limits<double>::epsilon() * 10.) {
55  Eigen::Matrix2cd exp2 = Eigen::Matrix2cd(
56  Eigen::DiagonalMatrix<complex_t, 2>({std::exp(beta_pp), std::exp(-beta_pp)}));
57  return Eigen::Matrix2cd{exp1 * QL * exp2 * QR};
58  }
59 
60  return exp1;
61  };
62 
63  const Eigen::Matrix2cd roughness_sum = roughness_matrix(1.);
64  const Eigen::Matrix2cd roughness_diff = roughness_matrix(-1.);
65 
66  return {roughness_sum, roughness_diff};
67 }
constexpr complex_t I
Definition: Complex.h:21
std::complex< double > complex_t
Definition: Complex.h:20
Eigen::Vector2cd m_lambda
wave propagation direction (-1 for direct one, 1 for time reverse)

References anonymous_namespace{SpecularMagneticNewNCStrategy.cpp}::checkForUnderflow(), I, MatrixRTCoefficients_v3::m_b, MatrixRTCoefficients_v3::m_lambda, and BasicVector3D< T >::x().

Referenced by computeBackwardsSubmatrices().

Here is the call graph for this function:

◆ computeBackwardsSubmatrices()

std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > SpecularMagneticNewNCStrategy::computeBackwardsSubmatrices ( const MatrixRTCoefficients_v3 coeff_i,
const MatrixRTCoefficients_v3 coeff_i1,
double  sigma 
) const
privatevirtual

Implements SpecularMagneticNewStrategy.

Definition at line 70 of file SpecularMagneticNewNCStrategy.cpp.

73 {
74  Eigen::Matrix2cd roughness_sum{Eigen::Matrix2cd::Identity()};
75  Eigen::Matrix2cd roughness_diff{Eigen::Matrix2cd::Identity()};
76  if (sigma != 0.) {
77  const auto ret = computeRoughnessMatrices(coeff_i, coeff_i1, sigma);
78  roughness_sum = std::get<0>(ret);
79  roughness_diff = std::get<1>(ret);
80  }
81 
82  const auto P = Eigen::Matrix2cd(coeff_i.computeInverseP() * coeff_i1.computeP());
83  const auto mp = 0.5 * (Eigen::Matrix2cd::Identity() + P) * roughness_diff;
84  const auto mm = 0.5 * (Eigen::Matrix2cd::Identity() - P) * roughness_sum;
85 
86  return {mp, mm};
87 }
Eigen::Matrix2cd computeInverseP() const
Eigen::Matrix2cd computeP() const
std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeRoughnessMatrices(const MatrixRTCoefficients_v3 &coeff_i, const MatrixRTCoefficients_v3 &coeff_i1, double sigma) const

References MatrixRTCoefficients_v3::computeInverseP(), MatrixRTCoefficients_v3::computeP(), and computeRoughnessMatrices().

Here is the call graph for this function:

◆ Execute() [1/2]

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

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

Implements ISpecularStrategy.

Definition at line 35 of file SpecularMagneticNewStrategy.cpp.

37 {
38  return Execute(slices, KzComputation::computeReducedKz(slices, k));
39 }
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(), and SpecularMagneticNewStrategy::Execute().

Referenced by SpecularMagneticNewStrategy::Execute().

Here is the call graph for this function:

◆ Execute() [2/2]

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

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 42 of file SpecularMagneticNewStrategy.cpp.

44 {
45  if (slices.size() != kz.size())
46  throw std::runtime_error("Number of slices does not match the size of the kz-vector");
47 
49  for (auto& coeff : computeTR(slices, kz))
50  result.push_back(std::make_unique<MatrixRTCoefficients_v3>(coeff));
51 
52  return result;
53 }
std::vector< std::unique_ptr< const ILayerRTCoefficients > > coeffs_t
std::vector< MatrixRTCoefficients_v3 > computeTR(const std::vector< Slice > &slices, const std::vector< complex_t > &kzs) const

References SpecularMagneticNewStrategy::computeTR().

Here is the call graph for this function:

◆ computeTR()

std::vector< MatrixRTCoefficients_v3 > SpecularMagneticNewStrategy::computeTR ( const std::vector< Slice > &  slices,
const std::vector< complex_t > &  kzs 
) const
privateinherited

Definition at line 56 of file SpecularMagneticNewStrategy.cpp.

58 {
59  const size_t N = slices.size();
60 
61  if (slices.size() != kzs.size())
62  throw std::runtime_error(
63  "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
64  if (slices.empty())
65  return {};
66 
67  std::vector<MatrixRTCoefficients_v3> result;
68  result.reserve(N);
69 
70  const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0; // save sign to restore it later
71 
72  auto B_0 = slices.front().bField();
73  result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0}, 0.0);
74  for (size_t i = 1, size = slices.size(); i < size; ++i) {
75  auto B = slices[i].bField() - B_0;
76  auto magnetic_SLD = magneticSLD(B);
77  result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)),
78  B.mag() > eps ? B / B.mag() : kvector_t{0.0, 0.0, 0.0}, magnetic_SLD);
79  }
80 
81  if (N == 1) {
82  result[0].m_T = Eigen::Matrix2cd::Identity();
83  result[0].m_R = Eigen::Matrix2cd::Zero();
84  return result;
85 
86  } else if (kzs[0] == 0.) {
87  result[0].m_T = Eigen::Matrix2cd::Identity();
88  result[0].m_R = -Eigen::Matrix2cd::Identity();
89  for (size_t i = 1; i < N; ++i) {
90  result[i].m_T.setZero();
91  result[i].m_R.setZero();
92  }
93  return result;
94  }
95 
96  calculateUpwards(result, slices);
97 
98  return result;
99 }
void calculateUpwards(std::vector< MatrixRTCoefficients_v3 > &coeff, const std::vector< Slice > &slices) const
Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag)
Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd &eigenvs)

References SpecularMagneticNewStrategy::calculateUpwards(), anonymous_namespace{SpecularMagneticNewStrategy.cpp}::checkForUnderflow(), anonymous_namespace{SpecularMagneticNewStrategy.cpp}::eigenvalues(), anonymous_namespace{SpecularMagneticNewStrategy.cpp}::eps, and anonymous_namespace{SpecularMagneticNewStrategy.cpp}::magneticSLD().

Referenced by SpecularMagneticNewStrategy::Execute().

Here is the call graph for this function:

◆ calculateUpwards()

void SpecularMagneticNewStrategy::calculateUpwards ( std::vector< MatrixRTCoefficients_v3 > &  coeff,
const std::vector< Slice > &  slices 
) const
privateinherited

Definition at line 101 of file SpecularMagneticNewStrategy.cpp.

103 {
104  const auto N = slices.size();
105  std::vector<Eigen::Matrix2cd> SMatrices(N - 1);
106  std::vector<complex_t> Normalization(N - 1);
107 
108  // bottom boundary condition
109  coeff.back().m_T = Eigen::Matrix2cd::Identity();
110  coeff.back().m_R = Eigen::Matrix2cd::Zero();
111 
112  for (int i = N - 2; i >= 0; --i) {
113  double sigma = 0.;
114  if (const auto roughness = GetBottomRoughness(slices, i))
115  sigma = roughness->getSigma();
116 
117  // compute the 2x2 submatrices in the write-up denoted as P+, P- and delta
118  const auto mpmm = computeBackwardsSubmatrices(coeff[i], coeff[i + 1], sigma);
119  const Eigen::Matrix2cd mp = mpmm.first;
120  const Eigen::Matrix2cd mm = mpmm.second;
121 
122  const Eigen::Matrix2cd delta = coeff[i].computeDeltaMatrix(slices[i].thickness());
123 
124  // compute the rotation matrix
125  Eigen::Matrix2cd S, Si;
126  Si = mp + mm * coeff[i + 1].m_R;
127  S << Si(1, 1), -Si(0, 1), -Si(1, 0), Si(0, 0);
128  const complex_t norm = S(0, 0) * S(1, 1) - S(0, 1) * S(1, 0);
129  S = S * delta;
130 
131  // store the rotation matrix and normalization constant in order to rotate
132  // the coefficients for all lower slices at the end of the computation
133  SMatrices[i] = S;
134  Normalization[i] = norm;
135 
136  // compute the reflection matrix and
137  // rotate the polarization such that we have pure incoming states (T = I)
138  S /= norm;
139 
140  // T is always equal to the identity at this point, no need to store
141  coeff[i].m_R = delta * (mm + mp * coeff[i + 1].m_R) * S;
142  }
143 
144  // now correct all amplitudes in forward direction by dividing with the remaining
145  // normalization constants. In addition rotate the polarization by the amount
146  // that was rotated above the current interface
147  // if the normalization overflows, all amplitudes below that point are set to zero
148  complex_t dumpingFactor = 1;
149  Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity();
150  for (size_t i = 1; i < N; ++i) {
151  dumpingFactor = dumpingFactor * Normalization[i - 1];
152  S = SMatrices[i - 1] * S;
153 
154  if (std::isinf(std::norm(dumpingFactor))) {
155  std::for_each(coeff.begin() + i, coeff.end(), [](auto& coeff) {
156  coeff.m_T = Eigen::Matrix2cd::Zero();
157  coeff.m_R = Eigen::Matrix2cd::Zero();
158  });
159  break;
160  }
161 
162  coeff[i].m_T = S / dumpingFactor; // T * S omitted, since T is always I
163  coeff[i].m_R *= S / dumpingFactor;
164  }
165 }
virtual std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeBackwardsSubmatrices(const MatrixRTCoefficients_v3 &coeff_i, const MatrixRTCoefficients_v3 &coeff_i1, double sigma) const =0
double Si(double x)
Sine integral function: .
const LayerRoughness * GetBottomRoughness(const std::vector< Slice > &slices, const size_t slice_index)

References SpecularMagneticNewStrategy::computeBackwardsSubmatrices(), anonymous_namespace{SpecularMagneticNewStrategy.cpp}::GetBottomRoughness(), and MathFunctions::Si().

Referenced by SpecularMagneticNewStrategy::computeTR().

Here is the call graph for this function:

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