40                                   const std::vector<complex_t>& kz)
 const 
   42     if (slices.size() != kz.size())
 
   43         throw std::runtime_error(
"Number of slices does not match the size of the kz-vector");
 
   47         result.push_back(std::make_unique<MatrixRTCoefficients_v2>(coeff));
 
   52 std::vector<MatrixRTCoefficients_v2>
 
   54                                     const std::vector<complex_t>& kzs)
 
   57         throw std::runtime_error(
"Edge case k_z = 0 not implemented");
 
   59     if (slices.size() != kzs.size())
 
   60         throw std::runtime_error(
 
   61             "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
 
   65     std::vector<MatrixRTCoefficients_v2> result;
 
   66     result.reserve(slices.size());
 
   68     const double kz_sign = kzs.front().real() > 0.0 ? 1.0 : -1.0; 
 
   71     for (
size_t i = 1, size = slices.size(); i < size; ++i) {
 
   76     if (result.front().m_lambda == Eigen::Vector2cd::Zero()) {
 
   77         std::for_each(result.begin(), result.end(), [](
auto& coeff) { setNoTransmission(coeff); });
 
   81     std::for_each(result.begin(), result.end(), [](
auto& coeff) { calculateTR(coeff); });
 
   90     const double b = coeff.
m_b.
mag();
 
   96     const double bpbz = b + coeff.
m_b.
z();
 
   97     const double bmbz = b - coeff.
m_b.
z();
 
  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;
 
  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);
 
  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;
 
  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);
 
  124     coeff.
T1 = Eigen::Matrix4cd::Zero();
 
  125     coeff.
R1 = Eigen::Matrix4cd::Zero();
 
  126     coeff.
T2 = Eigen::Matrix4cd::Zero();
 
  127     coeff.
R2 = Eigen::Matrix4cd::Zero();
 
  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;
 
  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;
 
  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;
 
  146     coeff.
m_w_plus = Eigen::Vector4cd::Zero();
 
  147     coeff.
m_w_min = Eigen::Vector4cd::Zero();
 
  148     coeff.
T1 = Eigen::Matrix4cd::Identity() / 4.0;
 
  158     const double b_mag = coeff.
m_b.
mag();
 
  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;
 
  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;
 
  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;
 
  182     std::vector<MatrixRTCoefficients_v2>& coeff, 
const std::vector<Slice>& slices)
 
  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());
 
  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();
 
  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;
 
  201         auto S = Snorm.first;
 
  202         auto norm = Snorm.second;
 
  205         Normalization[i] = norm;
 
  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;
 
  215         coeff[i].m_w_plus = std::move(w_plus);
 
  216         coeff[i].m_w_min = std::move(w_min);
 
  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;
 
  225         if (std::isinf(std::norm(dumpingFactor))) {
 
  227             std::for_each(coeff.begin() + i, coeff.end(),
 
  228                           [](
auto& coeff) { setNoTransmission(coeff); });
 
  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;
 
  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;
 
  240         coeff[i].m_w_plus = std::move(w_plus);
 
  241         coeff[i].m_w_min = std::move(w_min);
 
  245 std::pair<Eigen::Matrix2cd, complex_t>
 
  248     const Eigen::Vector2cd Ta = coeff.
T1plus() + coeff.
T2plus();
 
  249     const Eigen::Vector2cd Tb = coeff.
T1min() + coeff.
T2min();
 
  252     S << Ta(0), Tb(0), Ta(1), Tb(1);
 
  254     Eigen::Matrix2cd SInverse;
 
  255     SInverse << S(1, 1), -S(0, 1), -S(1, 0), S(0, 0);
 
  258     const complex_t denominator = S(0, 0) * d1 - d2 * S(0, 1);
 
  260     return {SInverse, denominator};
 
  273     return {
I * std::sqrt(a + b_mag), 
I * std::sqrt(a - b_mag)};
 
  278     auto lambda = [](
complex_t value) { 
return std::abs(value) < 1e-40 ? 1e-40 : value; };
 
  279     return {lambda(eigenvs(0)), lambda(eigenvs(1))};
 
  284     if (exponent.imag() > -std::log(std::numeric_limits<double>::min()))
 
  286     return std::exp(
I * exponent);
 
std::complex< double > complex_t
 
Declares functions in namespace KzComputation.
 
constexpr double magnetic_prefactor
 
Defines the values of physical constants (SI)
 
Defines class SpecularMagneticStrategy.
 
double mag() const
Returns magnitude of the vector.
 
T z() const
Returns z-component in cartesian coordinate system.
 
T y() const
Returns y-component in cartesian coordinate system.
 
T x() const
Returns x-component in cartesian coordinate system.
 
std::vector< std::unique_ptr< const ILayerRTCoefficients > > coeffs_t
 
Specular reflection and transmission coefficients in a layer in case of magnetic interactions between...
 
Eigen::Vector2cd T2plus() const override
 
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::Vector2cd T2min() const override
 
Eigen::Matrix4cd R1
matrix selecting the reflected part of the first eigenmode
 
Eigen::Vector2cd T1plus() const override
The following functions return the transmitted and reflected amplitudes for different incoming beam p...
 
Eigen::Vector4cd m_w_plus
boundary values for up-polarization
 
Eigen::Vector4cd m_w_min
boundary values for down-polarization
 
Eigen::Vector2cd T1min() const override
 
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)
 
static std::vector< MatrixRTCoefficients_v2 > computeTR(const std::vector< Slice > &slices, const std::vector< complex_t > &kzs)
 
static void nullifyBottomReflection(MatrixRTCoefficients_v2 &coeff)
initializes reflectionless bottom boundary condition.
 
static void setNoTransmission(MatrixRTCoefficients_v2 &coeff)
 
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...
 
static void calculateTR(MatrixRTCoefficients_v2 &coeff)
Computes frobenius matrices for multilayer solution.
 
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.
 
static std::pair< Eigen::Matrix2cd, complex_t > findNormalizationCoefficients(const MatrixRTCoefficients_v2 &coeff)
finds linear coefficients for normalizing transmitted wave to unity.
 
std::vector< complex_t > computeReducedKz(const std::vector< Slice > &slices, kvector_t k)
 
constexpr double g_factor_n
neutron g-factor
 
constexpr double h_bar
Reduced Plank constant, J s.
 
constexpr double m_n
Neutron mass, kg.
 
constexpr double mu_N
Nuclear magneton ( ), J/T.
 
complex_t GetImExponential(complex_t exponent)
 
Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag)
 
kvector_t magneticImpact(kvector_t B_field)
 
Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd &eigenvs)