31 const auto eps = std::numeric_limits<double>::epsilon() * 10.;
33 double magneticSLD(R3 B_field)
38 Spinor eigenvalues(complex_t kz,
double magnetic_SLD)
40 const complex_t a = kz * kz;
41 return {std::sqrt(a - 4. *
M_PI * magnetic_SLD), std::sqrt(a + 4. *
M_PI * magnetic_SLD)};
46 auto lambda = [](complex_t value) {
return std::abs(value) < 1e-40 ? 1e-40 : value; };
47 return {lambda(eigenvs.
u), lambda(eigenvs.
v)};
50 std::pair<SpinMatrix, SpinMatrix> computeBackwardsSubmatrices(
const MatrixFlux& coeff_i,
55 if (r_model == RoughnessModel::NEVOT_CROCE)
61 void calculateUpwards(std::vector<MatrixFlux>& coeff,
const SliceStack& slices,
64 const auto N = slices.size();
65 std::vector<SpinMatrix> SMatrices(
N - 1);
66 std::vector<complex_t> Normalization(
N - 1);
72 for (
size_t i =
N - 1; i > 0; --i) {
75 sigma = roughness->sigma();
78 const auto [mp, mm] = computeBackwardsSubmatrices(coeff[i - 1], coeff[i], sigma, r_model);
80 const SpinMatrix delta = coeff[i - 1].computeDeltaMatrix(slices[i - 1].thicknessOr0());
85 const complex_t norm = S.determinant();
91 Normalization[i - 1] = norm;
98 coeff[i - 1].m_R = delta * (mm + mp * coeff[i].m_R) * S;
105 complex_t dumpingFactor = 1;
107 for (
size_t i = 1; i <
N; ++i) {
108 dumpingFactor = dumpingFactor * Normalization[i - 1];
109 S = SMatrices[i - 1] * S;
111 if (std::isinf(std::norm(dumpingFactor))) {
112 std::for_each(coeff.begin() + i, coeff.end(), [](
auto& coeff) {
113 coeff.m_T = SpinMatrix();
114 coeff.m_R = SpinMatrix();
119 coeff[i].m_T = S / dumpingFactor;
120 coeff[i].m_R *= S / dumpingFactor;
124 std::vector<MatrixFlux> computeFlux(
const SliceStack& slices,
const std::vector<complex_t>& kzs,
127 const size_t N = slices.size();
129 if (slices.size() != kzs.size())
130 throw std::runtime_error(
131 "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside.");
135 std::vector<MatrixFlux> result;
138 const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0;
140 auto B_0 = slices.front().bField();
141 result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), R3{0.0, 0.0, 0.0}, 0.0);
142 for (
size_t i = 1; i < slices.size(); ++i) {
143 auto B = (forward ? +1 : -1) * (slices[i].bField() - B_0);
144 auto magnetic_SLD = magneticSLD(B);
145 result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)),
146 B.mag() > eps ? B / B.mag() : R3{0.0, 0.0, 0.0}, magnetic_SLD);
158 for (
size_t i = 1; i <
N; ++i) {
165 calculateUpwards(result, slices, r_model);
178 if (slices.size() > 1 && k.z() > 0)
179 throw std::runtime_error(
180 "source or detector below horizon not yet implemented for polarized scattering");
182 ASSERT(slices.size() == kz.size());
185 for (
auto& coeff : computeFlux(slices, kz, slices.
roughnessModel(), forward))
186 result.emplace_back(std::make_unique<const MatrixFlux>(coeff));
192 const std::vector<complex_t>& kzs,
bool forward)
196 ASSERT(slices.size() == kzs.size());
197 const auto N = slices.size();
203 auto B_0 = slices.front().bField();
204 const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0;
206 auto createCoeff = [&slices, &kzs, kz_sign, B_0, forward](
size_t i) {
207 const auto B = (forward ? +1 : -1) * (slices[i].bField() - B_0);
208 const auto magnetic_SLD = magneticSLD(B);
210 return MatrixFlux(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)),
211 B.mag() > eps ? B / B.mag() : R3{0.0, 0.0, 0.0}, magnetic_SLD);
214 auto c_i1 = createCoeff(
N - 1);
219 for (
size_t i =
N - 1; i > 0; --i) {
220 auto c_i = createCoeff(i - 1);
224 sigma = roughness->sigma();
227 const auto [mp, mm] = computeBackwardsSubmatrices(c_i, c_i1, sigma, r_model);
229 const SpinMatrix delta = c_i.computeDeltaMatrix(slices[i - 1].thicknessOr0());
235 S = S * (delta / norm);
237 c_i.m_R = delta * (mm + mp * c_i1.m_R) * S;
Defines the macro ASSERT.
#define ASSERT(condition)
Defines namespace Compute::SpecularMagnetic.
std::vector< std::unique_ptr< const IFlux > > Fluxes
Declares functions in namespace ComputateKz.
Defines class LayerRoughness.
constexpr double magnetic_prefactor
Defines class MatrixFlux.
Defines the values of physical constants (SI)
Defines class SliceStack.
Defines namespace MagneticNevotCroceTransition.
Defines namespace TransitionMagneticTanh.
Specular reflection and transmission coefficients in a layer in case of magnetic interactions between...
const LayerRoughness * bottomRoughness(size_t i_slice) const
RoughnessModel roughnessModel() const
static SpinMatrix Diag(complex_t a_, complex_t d_)
complex_t determinant() const
std::vector< complex_t > computeReducedKz(const SliceStack &slices, R3 k)
Computes kz values from known k vector and slices with the following assumptions:
std::pair< SpinMatrix, SpinMatrix > backwardsSubmatrices(const MatrixFlux &coeff_i, const MatrixFlux &coeff_i1, double sigma)
Fluxes fluxes(const SliceStack &slices, const R3 &k, bool forward)
Computes refraction angle reflection/transmission coefficients for given sliced sample and wavevector...
SpinMatrix topLayerR(const SliceStack &slices, const std::vector< complex_t > &kzs, bool forward)
Computes the Fresnel R coefficient for the top layer only Introduced in order to speed up pure reflec...
std::pair< SpinMatrix, SpinMatrix > backwardsSubmatrices(const MatrixFlux &coeff_i, const MatrixFlux &coeff_i1, double sigma)
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.