BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularMagneticNCStrategy.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sample/Specular/SpecularMagneticNCStrategy.cpp
6 //! @brief Implements class SpecularMagneticNCStrategy.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2020
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 
17 namespace {
18 complex_t checkForUnderflow(complex_t val);
19 }
20 
21 std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> SpecularMagneticNCStrategy::computeRoughnessMatrices(
22  const MatrixRTCoefficients& coeff_i, const MatrixRTCoefficients& coeff_i1, double sigma) const
23 {
24  complex_t beta_i = coeff_i.m_lambda(1) - coeff_i.m_lambda(0);
25  complex_t beta_i1 = coeff_i1.m_lambda(1) - coeff_i1.m_lambda(0);
26 
27  auto roughness_matrix = [sigma, &coeff_i, &coeff_i1, beta_i, beta_i1](double sign) {
28  const complex_t alpha_p = coeff_i1.m_lambda(0) + coeff_i1.m_lambda(1)
29  + sign * (coeff_i.m_lambda(0) + coeff_i.m_lambda(1));
30  auto b_p_vec = beta_i1 * coeff_i1.m_b + sign * beta_i * coeff_i.m_b;
31 
32  auto square = [](auto& v) { return v.x() * v.x() + v.y() * v.y() + v.z() * v.z(); };
33  complex_t beta_p = std::sqrt(checkForUnderflow(square(b_p_vec)));
34  b_p_vec /= beta_p;
35 
36  const complex_t alpha_pp = -(alpha_p * alpha_p + beta_p * beta_p) * sigma * sigma / 8.;
37  const complex_t beta_pp = -alpha_p * beta_p * sigma * sigma / 4.;
38 
39  Eigen::Matrix2cd QL, QR;
40 
41  const complex_t factor1 = std::sqrt(2. * (1. + b_p_vec.z()));
42  const complex_t factor2 = std::sqrt(2. * (1. - b_p_vec.z()));
43  QL << (b_p_vec.z() + 1.) / factor1, (b_p_vec.z() - 1.) / factor2,
44  (b_p_vec.x() + I * b_p_vec.y()) / factor1, (b_p_vec.x() + I * b_p_vec.y()) / factor2;
45  QR << (b_p_vec.z() + 1.) / factor1, (b_p_vec.x() - I * b_p_vec.y()) / factor1,
46  (b_p_vec.z() - 1.) / factor2, (b_p_vec.x() - I * b_p_vec.y()) / factor2;
47 
48  const Eigen::Matrix2cd exp1 =
49  Eigen::DiagonalMatrix<complex_t, 2>({std::exp(alpha_pp), std::exp(alpha_pp)});
50 
51  if (std::abs(beta_p) > std::numeric_limits<double>::epsilon() * 10.) {
52  Eigen::Matrix2cd exp2 = Eigen::Matrix2cd(
53  Eigen::DiagonalMatrix<complex_t, 2>({std::exp(beta_pp), std::exp(-beta_pp)}));
54  return Eigen::Matrix2cd{exp1 * QL * exp2 * QR};
55  }
56 
57  return exp1;
58  };
59 
60  const Eigen::Matrix2cd roughness_sum = roughness_matrix(1.);
61  const Eigen::Matrix2cd roughness_diff = roughness_matrix(-1.);
62 
63  return {roughness_sum, roughness_diff};
64 }
65 
66 std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd>
68  const MatrixRTCoefficients& coeff_i1,
69  double sigma) const
70 {
71  Eigen::Matrix2cd roughness_sum{Eigen::Matrix2cd::Identity()};
72  Eigen::Matrix2cd roughness_diff{Eigen::Matrix2cd::Identity()};
73  if (sigma != 0.) {
74  const auto ret = computeRoughnessMatrices(coeff_i, coeff_i1, sigma);
75  roughness_sum = std::get<0>(ret);
76  roughness_diff = std::get<1>(ret);
77  }
78 
79  const auto P = Eigen::Matrix2cd(coeff_i.computeInverseP() * coeff_i1.computeP());
80  const auto mp = 0.5 * (Eigen::Matrix2cd::Identity() + P) * roughness_diff;
81  const auto mm = 0.5 * (Eigen::Matrix2cd::Identity() - P) * roughness_sum;
82 
83  return {mp, mm};
84 }
85 
86 namespace {
87 complex_t checkForUnderflow(complex_t val)
88 {
89  return std::abs(val.imag()) < 1e-80 && val.real() < 0 ? complex_t(val.real(), 1e-40) : val;
90 }
91 } // namespace
constexpr complex_t I
Definition: Complex.h:21
std::complex< double > complex_t
Definition: Complex.h:20
Defines class SpecularMagneticNCStrategy.
T x() const
Returns x-component in cartesian coordinate system.
Definition: BasicVector3D.h:63
Specular reflection and transmission coefficients in a layer in case of magnetic interactions between...
Eigen::Matrix2cd computeInverseP() const
Eigen::Vector2cd m_lambda
wave propagation direction (-1 for direct one, 1 for time reverse)
kvector_t m_b
unit magnetic field vector
Eigen::Matrix2cd computeP() const
std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeRoughnessMatrices(const MatrixRTCoefficients &coeff_i, const MatrixRTCoefficients &coeff_i1, double sigma) const
virtual std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeBackwardsSubmatrices(const MatrixRTCoefficients &coeff_i, const MatrixRTCoefficients &coeff_i1, double sigma) const