22 Eigen::Vector2cd eigenvalues(
complex_t kz,
double b_mag);
23 Eigen::Vector2cd checkForUnderflow(
const Eigen::Vector2cd& eigenvs);
39 const std::vector<complex_t>& kz)
const
41 if (slices.size() != kz.size())
42 throw std::runtime_error(
"Number of slices does not match the size of the kz-vector");
46 result.push_back(std::make_unique<MatrixRTCoefficients_v2>(coeff));
51 std::variant<complex_t, Eigen::Matrix2cd>
53 const std::vector<complex_t>& kz)
const
55 throw std::runtime_error(
"Not implemented");
58 std::vector<MatrixRTCoefficients_v2>
60 const std::vector<complex_t>& kzs)
63 throw std::runtime_error(
"Edge case k_z = 0 not implemented");
65 if (slices.size() != kzs.size())
66 throw std::runtime_error(
67 "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
71 std::vector<MatrixRTCoefficients_v2> result;
72 result.reserve(slices.size());
74 const double kz_sign = kzs.front().real() > 0.0 ? 1.0 : -1.0;
75 const kvector_t b_0 = magneticImpact(slices.front().bField());
76 result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0),
kvector_t{0.0, 0.0, 0.0});
77 for (
size_t i = 1, size = slices.size(); i < size; ++i) {
78 kvector_t b = magneticImpact(slices[i].bField()) - b_0;
79 result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], b.
mag())), b);
82 if (result.front().m_lambda == Eigen::Vector2cd::Zero()) {
83 std::for_each(result.begin(), result.end(), [](
auto& coeff) { setNoTransmission(coeff); });
87 std::for_each(result.begin(), result.end(), [](
auto& coeff) { calculateTR(coeff); });
96 const double b = coeff.
m_b.
mag();
102 const double bpbz = b + coeff.
m_b.
z();
103 const double bmbz = b - coeff.
m_b.
z();
110 T1 << bmbz, -bxmby, -bmbz * l_1, bxmby * l_1, -bxpby, bpbz, bxpby * l_1, -bpbz * l_1,
111 -bmbz / l_1, bxmby / l_1, bmbz, -bxmby, bxpby / l_1, -bpbz / l_1, -bxpby, bpbz;
115 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),
116 -T1(2, 0), -T1(2, 1), T1(2, 2), T1(2, 3), -T1(3, 0), -T1(3, 1), T1(3, 2), T1(3, 3);
119 T2 << bpbz, bxmby, -bpbz * l_2, -bxmby * l_2, bxpby, bmbz, -bxpby * l_2, -bmbz * l_2,
120 -bpbz / l_2, -bxmby / l_2, bpbz, bxmby, -bxpby / l_2, -bmbz / l_2, bxpby, bmbz;
124 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),
125 -T2(2, 0), -T2(2, 1), T2(2, 2), T2(2, 3), -T2(3, 0), -T2(3, 1), T2(3, 2), T2(3, 3);
130 coeff.
T1 = Eigen::Matrix4cd::Zero();
131 coeff.
R1 = Eigen::Matrix4cd::Zero();
132 coeff.
T2 = Eigen::Matrix4cd::Zero();
133 coeff.
R2 = Eigen::Matrix4cd::Zero();
138 Eigen::Matrix3cd Tblock;
139 Tblock << 0.5, 0.0, -0.5 * eigen_value, 0.0, 0.0, 0.0, -0.5 / eigen_value, 0.0, 0.5;
141 Eigen::Matrix3cd Rblock;
142 Rblock << 0.5, 0.0, 0.5 * eigen_value, 0.0, 0.0, 0.0, 0.5 / eigen_value, 0.0, 0.5;
144 coeff.
T1.block<3, 3>(1, 1) = Tblock;
145 coeff.
R1.block<3, 3>(1, 1) = Rblock;
146 coeff.
T2.block<3, 3>(0, 0) = Tblock;
147 coeff.
R2.block<3, 3>(0, 0) = Rblock;
152 coeff.
m_w_plus = Eigen::Vector4cd::Zero();
153 coeff.
m_w_min = Eigen::Vector4cd::Zero();
154 coeff.
T1 = Eigen::Matrix4cd::Identity() / 4.0;
164 const double b_mag = coeff.
m_b.
mag();
169 coeff.
m_w_plus << -l_1, 0.0, 1.0, 0.0;
170 coeff.
m_w_min << 0.0, -l_1, 0.0, 1.0;
175 coeff.
m_w_min(0) = (b.
x() -
I * b.
y()) * (l_1 - l_2) / 2.0 / b_mag;
176 coeff.
m_w_min(1) = b.
z() * (l_2 - l_1) / 2.0 / b_mag - (l_1 + l_2) / 2.0;
181 coeff.
m_w_plus(0) = -(l_1 + l_2) / 2.0 - b.
z() / (l_1 + l_2);
182 coeff.
m_w_plus(1) = (b.
x() +
I * b.
y()) * (l_1 - l_2) / 2.0 / b_mag;
188 std::vector<MatrixRTCoefficients_v2>& coeff,
const std::vector<Slice>& slices)
190 const int size =
static_cast<int>(coeff.size());
191 std::vector<Eigen::Matrix2cd> SMatrices(coeff.size());
192 std::vector<complex_t> Normalization(coeff.size());
194 for (
int index = size - 2; index >= 0; --index) {
195 const size_t i =
static_cast<size_t>(index);
196 const double t = slices[i].thickness();
197 const auto kz = coeff[i].getKz();
198 const Eigen::Matrix4cd l = coeff[i].R1 * GetImExponential(kz(0) * t)
199 + coeff[i].T1 * GetImExponential(-kz(0) * t)
200 + coeff[i].R2 * GetImExponential(kz(1) * t)
201 + coeff[i].T2 * GetImExponential(-kz(1) * t);
202 coeff[i].m_w_plus = l * coeff[i + 1].m_w_plus;
203 coeff[i].m_w_min = l * coeff[i + 1].m_w_min;
207 auto S = Snorm.first;
208 auto norm = Snorm.second;
211 Normalization[i] = norm;
218 const Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min;
219 const Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min;
221 coeff[i].m_w_plus = std::move(w_plus);
222 coeff[i].m_w_min = std::move(w_min);
226 Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity();
227 for (
size_t i = 1; i < coeff.size(); ++i) {
228 dumpingFactor = dumpingFactor * Normalization[i - 1];
229 S = SMatrices[i - 1] * S;
231 if (std::isinf(std::norm(dumpingFactor))) {
233 std::for_each(coeff.begin() + i, coeff.end(),
234 [](
auto& coeff) { setNoTransmission(coeff); });
238 const complex_t a_plus = S(0, 0) / dumpingFactor;
239 const complex_t b_plus = S(1, 0) / dumpingFactor;
240 const complex_t a_min = S(0, 1) / dumpingFactor;
241 const complex_t b_min = S(1, 1) / dumpingFactor;
243 Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min;
244 Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min;
246 coeff[i].m_w_plus = std::move(w_plus);
247 coeff[i].m_w_min = std::move(w_min);
251 std::pair<Eigen::Matrix2cd, complex_t>
254 const Eigen::Vector2cd Ta = coeff.
T1plus() + coeff.
T2plus();
255 const Eigen::Vector2cd Tb = coeff.
T1min() + coeff.
T2min();
258 S << Ta(0), Tb(0), Ta(1), Tb(1);
260 Eigen::Matrix2cd SInverse;
261 SInverse << S(1, 1), -S(0, 1), -S(1, 0), S(0, 0);
264 const complex_t denominator = S(0, 0) * d1 - d2 * S(0, 1);
266 return {SInverse, denominator};
275 Eigen::Vector2cd eigenvalues(
complex_t kz,
double b_mag)
278 return {
I * std::sqrt(a + b_mag),
I * std::sqrt(a - b_mag)};
281 Eigen::Vector2cd checkForUnderflow(
const Eigen::Vector2cd& eigenvs)
283 auto lambda = [](
complex_t value) {
return std::abs(value) < 1e-40 ? 1e-40 : value; };
284 return {lambda(eigenvs(0)), lambda(eigenvs(1))};
289 if (exponent.imag() > -std::log(std::numeric_limits<double>::min()))
291 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_v2.
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 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.
virtual std::variant< complex_t, Eigen::Matrix2cd > computeTopLayerR(const std::vector< Slice > &slices, const std::vector< complex_t > &kz) const override
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 std::vector< MatrixRTCoefficients_v2 > computeTR(const std::vector< Slice > &slices, const std::vector< complex_t > &kzs)
static void setNoTransmission(MatrixRTCoefficients_v2 &coeff)
static void calculateTR(MatrixRTCoefficients_v2 &coeff)
Computes frobenius matrices for multilayer solution.
static void calculateZeroFieldTR(MatrixRTCoefficients_v2 &coeff)
static void nullifyBottomReflection(MatrixRTCoefficients_v2 &coeff)
initializes reflectionless bottom boundary condition.
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.