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)