24 Eigen::Vector2cd eigenvalues(complex_t kz,
double b_mag);
25 Eigen::Vector2cd checkForUnderflow(
const Eigen::Vector2cd& eigenvs);
30 const auto eps = std::numeric_limits<double>::epsilon() * 10.;
31 const LayerRoughness* GetBottomRoughness(
const std::vector<Slice>& slices,
32 const size_t slice_index);
38 return Execute(slices, KzComputation::computeReducedKz(slices, k));
41 ISpecularStrategy::coeffs_t
43 const std::vector<complex_t>& kz)
const
45 if (slices.size() != kz.size())
46 throw std::runtime_error(
"Number of slices does not match the size of the kz-vector");
48 ISpecularStrategy::coeffs_t result;
49 for (
auto& coeff : computeTR(slices, kz))
50 result.push_back(std::make_unique<MatrixRTCoefficients_v3>(coeff));
55 std::vector<MatrixRTCoefficients_v3>
56 SpecularMagneticNewStrategy::computeTR(
const std::vector<Slice>& slices,
57 const std::vector<complex_t>& kzs)
const
59 const size_t N = slices.size();
61 if (slices.size() != kzs.size())
62 throw std::runtime_error(
63 "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
67 std::vector<MatrixRTCoefficients_v3> result;
70 const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0;
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);
82 result[0].m_T = Eigen::Matrix2cd::Identity();
83 result[0].m_R = Eigen::Matrix2cd::Zero();
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();
96 calculateUpwards(result, slices);
101 void SpecularMagneticNewStrategy::calculateUpwards(std::vector<MatrixRTCoefficients_v3>& coeff,
102 const std::vector<Slice>& slices)
const
104 const auto N = slices.size();
105 std::vector<Eigen::Matrix2cd> SMatrices(N - 1);
106 std::vector<complex_t> Normalization(N - 1);
109 coeff.back().m_T = Eigen::Matrix2cd::Identity();
110 coeff.back().m_R = Eigen::Matrix2cd::Zero();
112 for (
int i = N - 2; i >= 0; --i) {
114 if (
const auto roughness = GetBottomRoughness(slices, i))
115 sigma = roughness->getSigma();
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;
122 const Eigen::Matrix2cd delta = coeff[i].computeDeltaMatrix(slices[i].thickness());
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);
134 Normalization[i] = norm;
141 coeff[i].m_R = delta * (mm + mp * coeff[i + 1].m_R) * S;
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;
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();
162 coeff[i].m_T = S / dumpingFactor;
163 coeff[i].m_R *= S / dumpingFactor;
171 return magnetic_prefactor * B_field.
mag();
174 Eigen::Vector2cd eigenvalues(complex_t kz,
double magnetic_SLD)
176 const complex_t a = kz * kz;
177 return {std::sqrt(a - 4. * M_PI * magnetic_SLD), std::sqrt(a + 4. * M_PI * magnetic_SLD)};
180 Eigen::Vector2cd checkForUnderflow(
const Eigen::Vector2cd& eigenvs)
182 auto lambda = [](complex_t value) {
return std::abs(value) < 1e-40 ? 1e-40 : value; };
183 return {lambda(eigenvs(0)), lambda(eigenvs(1))};
186 const LayerRoughness* GetBottomRoughness(
const std::vector<Slice>& slices,
const size_t slice_index)
188 if (slice_index + 1 < slices.size())
189 return slices[slice_index + 1].topRoughness();
Declares functions in namespace KzComputation.
Defines class LayerRoughness.
Defines the values of physical constants (SI)
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.
Defines class SpecularMagneticNewStrategy.
double mag() const
Returns magnitude of the vector.
A roughness of interface between two layers.
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...
double Si(double x)
Sine integral function: .