23 Eigen::Vector2cd eigenvalues(
complex_t kz,
double b_mag);
24 Eigen::Vector2cd checkForUnderflow(
const Eigen::Vector2cd& eigenvs);
29 const auto eps = std::numeric_limits<double>::epsilon() * 10.;
30 const LayerRoughness* GetBottomRoughness(
const std::vector<Slice>& slices,
31 const size_t slice_index);
42 const std::vector<complex_t>& kz)
const
44 if (slices.size() != kz.size())
45 throw std::runtime_error(
"Number of slices does not match the size of the kz-vector");
49 result.push_back(std::make_unique<MatrixRTCoefficients>(coeff));
54 std::variant<complex_t, Eigen::Matrix2cd>
56 const std::vector<complex_t>& kzs)
const
58 if (slices.size() != kzs.size())
59 throw std::runtime_error(
"Number of slices does not match the size of the kz-vector");
61 const auto N = slices.size();
64 return Eigen::Matrix2cd::Zero();
66 return -Eigen::Matrix2cd::Identity();
68 auto B_0 = slices.front().bField();
69 const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0;
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);
76 B.mag() > eps ? B / B.mag() :
kvector_t{0.0, 0.0, 0.0}, magnetic_SLD);
79 auto c_i1 = createCoeff(N-1);
82 c_i1.m_R = Eigen::Matrix2cd::Zero();
84 for (
int i = N - 2; i >= 0; --i) {
85 auto c_i = createCoeff(i);
88 if (
const auto roughness = GetBottomRoughness(slices, i))
89 sigma = roughness->getSigma();
94 const Eigen::Matrix2cd delta = c_i.computeDeltaMatrix(slices[i].thickness());
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);
104 c_i.m_R = delta * (mm + mp * c_i1.m_R) * S;
110 std::vector<MatrixRTCoefficients>
112 const std::vector<complex_t>& kzs)
const
114 const size_t N = slices.size();
116 if (slices.size() != kzs.size())
117 throw std::runtime_error(
118 "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
122 std::vector<MatrixRTCoefficients> result;
125 const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0;
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);
137 result[0].m_T = Eigen::Matrix2cd::Identity();
138 result[0].m_R = Eigen::Matrix2cd::Zero();
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();
157 const std::vector<Slice>& slices)
const
159 const auto N = slices.size();
160 std::vector<Eigen::Matrix2cd> SMatrices(N - 1);
161 std::vector<complex_t> Normalization(N - 1);
164 coeff.back().m_T = Eigen::Matrix2cd::Identity();
165 coeff.back().m_R = Eigen::Matrix2cd::Zero();
167 for (
int i = N - 2; i >= 0; --i) {
169 if (
const auto roughness = GetBottomRoughness(slices, i))
170 sigma = roughness->getSigma();
175 const Eigen::Matrix2cd delta = coeff[i].computeDeltaMatrix(slices[i].thickness());
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);
187 Normalization[i] = norm;
194 coeff[i].m_R = delta * (mm + mp * coeff[i + 1].m_R) * S;
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;
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();
215 coeff[i].m_T = S / dumpingFactor;
216 coeff[i].m_R *= S / dumpingFactor;
226 Eigen::Vector2cd eigenvalues(
complex_t kz,
double magnetic_SLD)
229 return {std::sqrt(a - 4. *
M_PI * magnetic_SLD), std::sqrt(a + 4. *
M_PI * magnetic_SLD)};
232 Eigen::Vector2cd checkForUnderflow(
const Eigen::Vector2cd& eigenvs)
234 auto lambda = [](
complex_t value) {
return std::abs(value) < 1e-40 ? 1e-40 : value; };
235 return {lambda(eigenvs(0)), lambda(eigenvs(1))};
238 const LayerRoughness* GetBottomRoughness(
const std::vector<Slice>& slices,
const size_t slice_index)
240 if (slice_index + 1 < slices.size())
241 return slices[slice_index + 1].topRoughness();
std::complex< double > complex_t
Declares functions in namespace KzComputation.
Defines class LayerRoughness.
constexpr double magnetic_prefactor
Defines the values of physical constants (SI)
Defines class SpecularMagneticStrategy.
double mag() const
Returns magnitude of the vector.
std::vector< std::unique_ptr< const ILayerRTCoefficients > > coeffs_t
A roughness of interface between two layers.
Specular reflection and transmission coefficients in a layer in case of magnetic interactions between...
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 reflec...
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...
virtual std::pair< Eigen::Matrix2cd, Eigen::Matrix2cd > computeBackwardsSubmatrices(const MatrixRTCoefficients &coeff_i, const MatrixRTCoefficients &coeff_i1, double sigma) const =0
std::vector< MatrixRTCoefficients > computeTR(const std::vector< Slice > &slices, const std::vector< complex_t > &kzs) const
void calculateUpwards(std::vector< MatrixRTCoefficients > &coeff, const std::vector< Slice > &slices) const
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.