BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
SpecularMagneticStrategy Class Referenceabstract

Implements the magnetic Fresnel computation with Nevot-Croce roughness. More...

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

Public Types

using coefficient_entry_type = Eigen::Matrix2cd
 
using coefficient_pointer_type = std::unique_ptr< const coefficient_type >
 
using coefficient_type = MatrixRTCoefficients
 
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 > &kzs) const override
 Computes the Fresnel R coefficient for the top layer only Introduced in order to speed up pure reflectivity computations. More...
 
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...
 

Private Member Functions

void calculateUpwards (std::vector< MatrixRTCoefficients > &coeff, const std::vector< Slice > &slices) const
 
virtual std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeBackwardsSubmatrices (const MatrixRTCoefficients &coeff_i, const MatrixRTCoefficients &coeff_i1, double sigma) const =0
 
std::vector< MatrixRTCoefficientscomputeTR (const std::vector< Slice > &slices, const std::vector< complex_t > &kzs) 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 38 of file SpecularMagneticStrategy.h.

Member Typedef Documentation

◆ coefficient_entry_type

Definition at line 42 of file SpecularMagneticStrategy.h.

◆ coefficient_pointer_type

Definition at line 44 of file SpecularMagneticStrategy.h.

◆ coefficient_type

◆ coeffs_t

Member Function Documentation

◆ calculateUpwards()

void SpecularMagneticStrategy::calculateUpwards ( std::vector< MatrixRTCoefficients > &  coeff,
const std::vector< Slice > &  slices 
) const
private

Definition at line 156 of file SpecularMagneticStrategy.cpp.

158 {
159  const auto N = slices.size();
160  std::vector<Eigen::Matrix2cd> SMatrices(N - 1);
161  std::vector<complex_t> Normalization(N - 1);
162 
163  // bottom boundary condition
164  coeff.back().m_T = Eigen::Matrix2cd::Identity();
165  coeff.back().m_R = Eigen::Matrix2cd::Zero();
166 
167  for (int i = N - 2; i >= 0; --i) {
168  double sigma = 0.;
169  if (const auto roughness = GetBottomRoughness(slices, i))
170  sigma = roughness->getSigma();
171 
172  // compute the 2x2 submatrices in the write-up denoted as P+, P- and delta
173  const auto [mp, mm] = computeBackwardsSubmatrices(coeff[i], coeff[i + 1], sigma);
174 
175  const Eigen::Matrix2cd delta = coeff[i].computeDeltaMatrix(slices[i].thickness());
176 
177  // compute the rotation matrix
178  Eigen::Matrix2cd S, Si;
179  Si = mp + mm * coeff[i + 1].m_R;
180  S << Si(1, 1), -Si(0, 1), -Si(1, 0), Si(0, 0);
181  const complex_t norm = S(0, 0) * S(1, 1) - S(0, 1) * S(1, 0);
182  S = S * delta;
183 
184  // store the rotation matrix and normalization constant in order to rotate
185  // the coefficients for all lower slices at the end of the computation
186  SMatrices[i] = S;
187  Normalization[i] = norm;
188 
189  // compute the reflection matrix and
190  // rotate the polarization such that we have pure incoming states (T = I)
191  S /= norm;
192 
193  // T is always equal to the identity at this point, no need to store
194  coeff[i].m_R = delta * (mm + mp * coeff[i + 1].m_R) * S;
195  }
196 
197  // now correct all amplitudes in forward direction by dividing with the remaining
198  // normalization constants. In addition rotate the polarization by the amount
199  // that was rotated above the current interface
200  // if the normalization overflows, all amplitudes below that point are set to zero
201  complex_t dumpingFactor = 1;
202  Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity();
203  for (size_t i = 1; i < N; ++i) {
204  dumpingFactor = dumpingFactor * Normalization[i - 1];
205  S = SMatrices[i - 1] * S;
206 
207  if (std::isinf(std::norm(dumpingFactor))) {
208  std::for_each(coeff.begin() + i, coeff.end(), [](auto& coeff) {
209  coeff.m_T = Eigen::Matrix2cd::Zero();
210  coeff.m_R = Eigen::Matrix2cd::Zero();
211  });
212  break;
213  }
214 
215  coeff[i].m_T = S / dumpingFactor; // T * S omitted, since T is always I
216  coeff[i].m_R *= S / dumpingFactor;
217  }
218 }
std::complex< double > complex_t
Definition: Complex.h:20
virtual std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeBackwardsSubmatrices(const MatrixRTCoefficients &coeff_i, const MatrixRTCoefficients &coeff_i1, double sigma) const =0

References computeBackwardsSubmatrices().

Referenced by computeTR().

Here is the call graph for this function:

◆ computeBackwardsSubmatrices()

virtual std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> SpecularMagneticStrategy::computeBackwardsSubmatrices ( const MatrixRTCoefficients coeff_i,
const MatrixRTCoefficients coeff_i1,
double  sigma 
) const
privatepure virtual

◆ computeTopLayerR()

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

Computes the Fresnel R coefficient for the top layer only Introduced in order to speed up pure reflectivity computations.

Implements ISpecularStrategy.

Definition at line 55 of file SpecularMagneticStrategy.cpp.

57 {
58  if (slices.size() != kzs.size())
59  throw std::runtime_error("Number of slices does not match the size of the kz-vector");
60 
61  const auto N = slices.size();
62 
63  if(N == 1)
64  return Eigen::Matrix2cd::Zero();
65  else if(kzs[0] == 0.)
66  return -Eigen::Matrix2cd::Identity();
67 
68  auto B_0 = slices.front().bField();
69  const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0; // save sign to restore it later
70 
71  auto createCoeff = [&slices, &kzs, kz_sign, B_0](int i){
72  const auto B = slices[i].bField() - B_0;
73  const auto magnetic_SLD = magneticSLD(B);
74 
75  return MatrixRTCoefficients(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)),
76  B.mag() > eps ? B / B.mag() : kvector_t{0.0, 0.0, 0.0}, magnetic_SLD);
77  };
78 
79  auto c_i1 = createCoeff(N-1);
80 
81  // bottom boundary condition
82  c_i1.m_R = Eigen::Matrix2cd::Zero();
83 
84  for (int i = N - 2; i >= 0; --i) {
85  auto c_i = createCoeff(i);
86 
87  double sigma = 0.;
88  if (const auto roughness = GetBottomRoughness(slices, i))
89  sigma = roughness->getSigma();
90 
91  // compute the 2x2 submatrices in the write-up denoted as P+, P- and delta
92  const auto [mp, mm] = computeBackwardsSubmatrices(c_i, c_i1, sigma);
93 
94  const Eigen::Matrix2cd delta = c_i.computeDeltaMatrix(slices[i].thickness());
95 
96  // compute the rotation matrix
97  Eigen::Matrix2cd S, Si;
98  Si = mp + mm * c_i1.m_R;
99  S << Si(1, 1), -Si(0, 1), -Si(1, 0), Si(0, 0);
100  const complex_t norm = S(0, 0) * S(1, 1) - S(0, 1) * S(1, 0);
101  S = S * delta;
102  S /= norm;
103 
104  c_i.m_R = delta * (mm + mp * c_i1.m_R) * S;
105  c_i1 = c_i;
106  }
107  return c_i1.m_R;
108 }
Specular reflection and transmission coefficients in a layer in case of magnetic interactions between...

References computeBackwardsSubmatrices().

Here is the call graph for this function:

◆ computeTR()

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

Definition at line 111 of file SpecularMagneticStrategy.cpp.

113 {
114  const size_t N = slices.size();
115 
116  if (slices.size() != kzs.size())
117  throw std::runtime_error(
118  "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
119  if (slices.empty())
120  return {};
121 
122  std::vector<MatrixRTCoefficients> result;
123  result.reserve(N);
124 
125  const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0; // save sign to restore it later
126 
127  auto B_0 = slices.front().bField();
128  result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0}, 0.0);
129  for (size_t i = 1, size = slices.size(); i < size; ++i) {
130  auto B = slices[i].bField() - B_0;
131  auto magnetic_SLD = magneticSLD(B);
132  result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)),
133  B.mag() > eps ? B / B.mag() : kvector_t{0.0, 0.0, 0.0}, magnetic_SLD);
134  }
135 
136  if (N == 1) {
137  result[0].m_T = Eigen::Matrix2cd::Identity();
138  result[0].m_R = Eigen::Matrix2cd::Zero();
139  return result;
140 
141  } else if (kzs[0] == 0.) {
142  result[0].m_T = Eigen::Matrix2cd::Identity();
143  result[0].m_R = -Eigen::Matrix2cd::Identity();
144  for (size_t i = 1; i < N; ++i) {
145  result[i].m_T.setZero();
146  result[i].m_R.setZero();
147  }
148  return result;
149  }
150 
151  calculateUpwards(result, slices);
152 
153  return result;
154 }
void calculateUpwards(std::vector< MatrixRTCoefficients > &coeff, const std::vector< Slice > &slices) const

References calculateUpwards().

Referenced by Execute().

Here is the call graph for this function:

◆ 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 34 of file SpecularMagneticStrategy.cpp.

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

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

References computeTR().

Here is the call graph for this function:

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