BornAgain  1.18.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularMagneticOldStrategy.cpp
Go to the documentation of this file.
1 // ************************************************************************** //
2 //
3 // BornAgain: simulate and fit scattering at grazing incidence
4 //
5 //! @file Sample/Specular/SpecularMagneticOldStrategy.cpp
6 //! @brief Implements class SpecularMagneticOldStrategy.
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 
20 #include "Sample/Slice/Slice.h"
21 #include <Eigen/LU>
22 
23 namespace
24 {
25 void CalculateEigenvalues(const std::vector<Slice>& slices, const kvector_t k,
26  std::vector<MatrixRTCoefficients>& coeff);
27 void CalculateTransferAndBoundary(const std::vector<Slice>& slices,
28  std::vector<MatrixRTCoefficients>& coeff);
29 void SetForNoTransmission(std::vector<MatrixRTCoefficients>& coeff);
31 } // namespace
32 
34  const kvector_t& k) const
35 {
36  std::vector<MatrixRTCoefficients> result(slices.size());
37  CalculateEigenvalues(slices, k, result);
38  CalculateTransferAndBoundary(slices, result);
39 
40  coeffs_t resultConvert;
41  for (auto& coeff : result)
42  resultConvert.push_back(std::make_unique<MatrixRTCoefficients>(coeff));
43 
44  return resultConvert;
45 }
46 
48 SpecularMagneticOldStrategy::Execute(const std::vector<Slice>&, const std::vector<complex_t>&) const
49 {
50  throw std::runtime_error("Not implemented");
51 }
52 
53 namespace
54 {
55 void CalculateEigenvalues(const std::vector<Slice>& slices, const kvector_t k,
56  std::vector<MatrixRTCoefficients>& coeff)
57 {
58  double mag_k = k.mag();
59  double n_ref = slices[0].material().refractiveIndex(2 * M_PI / mag_k).real();
60  double sign_kz = k.z() > 0.0 ? -1.0 : 1.0;
61  for (size_t i = 0; i < coeff.size(); ++i) {
62  coeff[i].m_scatt_matrix = slices[i].polarizedReducedPotential(k, n_ref);
63  coeff[i].m_kt = mag_k * slices[i].thickness();
64  coeff[i].m_a = coeff[i].m_scatt_matrix.trace() / 2.0;
65  coeff[i].m_b_mag =
66  sqrt(coeff[i].m_a * coeff[i].m_a - coeff[i].m_scatt_matrix.determinant());
67  coeff[i].m_bz = (coeff[i].m_scatt_matrix(0, 0) - coeff[i].m_scatt_matrix(1, 1)) / 2.0;
68  complex_t rad0 = coeff[i].m_a - coeff[i].m_b_mag;
69  complex_t rad1 = coeff[i].m_a + coeff[i].m_b_mag;
70  // use small absorptive component for layers with i>0 if radicand becomes very small:
71  if (i > 0) {
72  if (std::abs(rad0) < 1e-40)
73  rad0 = I * 1e-40;
74  if (std::abs(rad1) < 1e-40)
75  rad1 = I * 1e-40;
76  }
77  coeff[i].lambda(0) = sqrt(rad0);
78  coeff[i].lambda(1) = sqrt(rad1);
79  coeff[i].kz = mag_k * coeff[i].lambda * sign_kz;
80  }
81 }
82 
83 // todo: avoid overflows (see SpecularMatrix.cpp)
84 void CalculateTransferAndBoundary(const std::vector<Slice>& slices,
85  std::vector<MatrixRTCoefficients>& coeff)
86 {
87  size_t N = coeff.size();
88  if (coeff[0].lambda == Eigen::Vector2cd::Zero() && N > 1) {
89  SetForNoTransmission(coeff);
90  return;
91  }
92 
93  // First, initialize bottom layer values to have no reflection
94  coeff[N - 1].initializeBottomLayerPhiPsi();
95  if (N > 1)
96  coeff[N - 1].calculateTRMatrices();
97 
98  coeff[0].calculateTRMatrices();
99  for (int signed_index = static_cast<int>(N) - 2; signed_index > 0; --signed_index) {
100  size_t i = static_cast<size_t>(signed_index);
101  double t = slices[i].thickness();
102  coeff[i].calculateTRMatrices();
103  Eigen::Matrix4cd l = coeff[i].R1m * GetImExponential(coeff[i].kz(0) * t)
104  + coeff[i].T1m * GetImExponential(-coeff[i].kz(0) * t)
105  + coeff[i].R2m * GetImExponential(coeff[i].kz(1) * t)
106  + coeff[i].T2m * GetImExponential(-coeff[i].kz(1) * t);
107  coeff[i].phi_psi_plus = l * coeff[i + 1].phi_psi_plus;
108  coeff[i].phi_psi_min = l * coeff[i + 1].phi_psi_min;
109  }
110  // If more than one layer, impose normalization and correct correspondence
111  // for spin-z polarization in top layer
112  if (N > 1) {
113  // First layer boundary is also top layer boundary:
114  coeff[0].phi_psi_plus = coeff[1].phi_psi_plus;
115  coeff[0].phi_psi_min = coeff[1].phi_psi_min;
116  // Normalize all boundary values such that top layer has unit wave
117  // amplitude for both spin up and down (and does not contain a
118  // transmitted wave amplitude for the opposite polarization)
119  Eigen::Vector2cd T0basisA = coeff[0].T1plus() + coeff[0].T2plus();
120  Eigen::Vector2cd T0basisB = coeff[0].T1min() + coeff[0].T2min();
121  complex_t cpA, cpB, cmA, cmB;
122  cpA = T0basisB(1);
123  cpB = -T0basisA(1);
124  cmA = T0basisB(0);
125  cmB = -T0basisA(0);
126  Eigen::Vector4cd phipsitemp = cpA * coeff[0].phi_psi_plus + cpB * coeff[0].phi_psi_min;
127  coeff[0].phi_psi_min = cmA * coeff[0].phi_psi_plus + cmB * coeff[0].phi_psi_min;
128  coeff[0].phi_psi_plus = phipsitemp;
129  Eigen::Vector2cd T0plusV = coeff[0].T1plus() + coeff[0].T2plus();
130  Eigen::Vector2cd T0minV = coeff[0].T1min() + coeff[0].T2min();
131  complex_t T0plus = T0plusV(0);
132  complex_t T0min = T0minV(1);
133  coeff[0].phi_psi_min = coeff[0].phi_psi_min / T0min;
134  coeff[0].phi_psi_plus = coeff[0].phi_psi_plus / T0plus;
135  for (size_t i = 1; i < N; ++i) {
136  phipsitemp = (cpA * coeff[i].phi_psi_plus + cpB * coeff[i].phi_psi_min) / T0plus;
137  coeff[i].phi_psi_min =
138  (cmA * coeff[i].phi_psi_plus + cmB * coeff[i].phi_psi_min) / T0min;
139  coeff[i].phi_psi_plus = phipsitemp;
140  }
141  }
142 }
143 
144 void SetForNoTransmission(std::vector<MatrixRTCoefficients>& coeff)
145 {
146  size_t N = coeff.size();
147  for (size_t i = 0; i < N; ++i) {
148  coeff[i].phi_psi_plus.setZero();
149  coeff[i].phi_psi_min.setZero();
150  coeff[i].T1m = Eigen::Matrix4cd::Identity() / 4.0;
151  coeff[i].R1m = coeff[i].T1m;
152  coeff[i].T2m = coeff[i].T1m;
153  coeff[i].R2m = coeff[i].T1m;
154  }
155 }
156 
158 {
159  if (exponent.imag() > -std::log(std::numeric_limits<double>::min()))
160  return 0.0;
161  return std::exp(I * exponent);
162 }
163 } // unnamed namespace
constexpr complex_t I
Definition: Complex.h:21
std::complex< double > complex_t
Definition: Complex.h:20
Defines class LayerInterface.
Defines class Layer.
#define M_PI
Definition: MathConstants.h:39
Defines class MultiLayer.
Defines class Slice.
Defines class SpecularMagneticOldStrategy.
Defines WavevectorInfo.
double mag() const
Returns magnitude of the vector.
T z() const
Returns z-component in cartesian coordinate system.
Definition: BasicVector3D.h:68
std::vector< std::unique_ptr< const ILayerRTCoefficients > > coeffs_t
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...
void CalculateTransferAndBoundary(const std::vector< Slice > &slices, std::vector< MatrixRTCoefficients > &coeff)
void CalculateEigenvalues(const std::vector< Slice > &slices, const kvector_t k, std::vector< MatrixRTCoefficients > &coeff)
void SetForNoTransmission(std::vector< MatrixRTCoefficients > &coeff)