diff --git a/Core/Algorithms/inc/SpecularMagnetic.h b/Core/Algorithms/inc/SpecularMagnetic.h new file mode 100644 index 0000000000000000000000000000000000000000..39e4684b5de98d12c107fe526ef8e43aebeb56e1 --- /dev/null +++ b/Core/Algorithms/inc/SpecularMagnetic.h @@ -0,0 +1,121 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Algorithms/inc/SpecularMagnetic.h +//! @brief Defines class SpecularMagnetic. +//! +//! @homepage http://apps.jcns.fz-juelich.de/BornAgain +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2013 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#ifndef SPECULARMAGNETIC_H_ +#define SPECULARMAGNETIC_H_ + +#include "Types.h" +#include "ISimulation.h" +#include "MultiLayer.h" + +#include <Eigen/Core> + +//! Implements the matrix formalism for the calculation of wave amplitudes of +//! the coherent wave solution in a multilayer with magnetization + +class SpecularMagnetic : public ISimulation +{ +public: + SpecularMagnetic() {} + + //! layer coefficients for matrix formalism + class LayerMatrixCoeff { + public: + LayerMatrixCoeff() {} + ~LayerMatrixCoeff() {} + Eigen::Vector2cd T1() const; + Eigen::Vector2cd R1() const; + Eigen::Vector2cd T2() const; + Eigen::Vector2cd R2() const; + // R, T - amplitudes of reflected and transmitted waves + Eigen::Vector2cd lambda; // positive eigenvalues of transfer matrix + Eigen::Vector2cd kz; + Eigen::Vector4cd phi_psi; // boundary values + Eigen::Matrix4cd l; + Eigen::Matrix4cd T1m; + Eigen::Matrix4cd R1m; + Eigen::Matrix4cd T2m; + Eigen::Matrix4cd R2m; + Eigen::Matrix2cd m_scatt_matrix; // scattering matrix + complex_t m_a; // polarization independent part + complex_t m_b_mag; // magnitude of polarization part + complex_t m_bz; // z-part of polarization scattering + void calculateTRMatrices(); + private: + void calculateTRWithoutMagnetization(); + }; + + //! multi layer coefficients for matrix formalism + class MultiLayerMatrixCoeff + { + public: + LayerMatrixCoeff& operator[](size_t i) { return m_data[i]; } + const LayerMatrixCoeff& operator[](size_t i) const { return m_data[i]; } + size_t size() const { return m_data.size(); } + void clear() { m_data.clear(); } + void resize(size_t size) { m_data.resize(size); } + private: + std::vector<LayerMatrixCoeff > m_data; + }; + + typedef MultiLayerMatrixCoeff MultiLayerCoeff_t; // set of layer coefficients for matrix formalism + + //! Calculates Fresnel coefficients for given multi layer and kvector + void execute(const MultiLayer& sample, const kvector_t& k, MultiLayerCoeff_t& coeff); + +private: +// std::vector<Eigen::Matrix2cd> m_roughness_pmatrices; + + void calculateEigenvalues(const MultiLayer& sample, const kvector_t& k, + MultiLayerCoeff_t& coeff) const; + void calculateTransferAndBoundary(const MultiLayer& sample, + const kvector_t& k, MultiLayerCoeff_t& coeff) const; +// Eigen::Matrix2cd calculatePMatrix(double sigma_eff, +// complex_t lambda_lower, complex_t lambda_upper) const; + Eigen::Matrix2cd getUnitMatrix() const; +// complex_t getPMatrixElement(complex_t sigma_lambda) const; + void setForNoTransmission(MultiLayerCoeff_t& coeff) const; + complex_t getImExponential(complex_t exponent) const; +}; + +inline Eigen::Vector2cd SpecularMagnetic::LayerMatrixCoeff::T1() const { + Eigen::Vector2cd result; + result(0) = T1m.row(2).dot(phi_psi); + result(1) = T1m.row(3).dot(phi_psi); + return result; +} + +inline Eigen::Vector2cd SpecularMagnetic::LayerMatrixCoeff::R1() const { + Eigen::Vector2cd result; + result(0) = R1m.row(2).dot(phi_psi); + result(1) = R1m.row(3).dot(phi_psi); + return result; +} + +inline Eigen::Vector2cd SpecularMagnetic::LayerMatrixCoeff::T2() const { + Eigen::Vector2cd result; + result(0) = T2m.row(2).dot(phi_psi); + result(1) = T2m.row(3).dot(phi_psi); + return result; +} + +inline Eigen::Vector2cd SpecularMagnetic::LayerMatrixCoeff::R2() const { + Eigen::Vector2cd result; + result(0) = R2m.row(2).dot(phi_psi); + result(1) = R2m.row(3).dot(phi_psi); + return result; +} + +#endif /* SPECULARMAGNETIC_H_ */ diff --git a/Core/Algorithms/src/SpecularMagnetic.cpp b/Core/Algorithms/src/SpecularMagnetic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7bdc6526fd20ffd1c345f74816c6ce16c8103ae --- /dev/null +++ b/Core/Algorithms/src/SpecularMagnetic.cpp @@ -0,0 +1,218 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file SpecularMagnetic.cpp +//! @brief Implements class SpecularMagnetic. +//! +//! @homepage http://apps.jcns.fz-juelich.de/BornAgain +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2013 +//! @authors Scientific Computing Group at MLZ Garching +//! @authors C. Durniak, G. Pospelov, W. Van Herck, J. Wuttke +// +// ************************************************************************** // + +#include "SpecularMagnetic.h" + +#include <Eigen/LU> + +void SpecularMagnetic::execute(const MultiLayer& sample, const kvector_t& k, + MultiLayerCoeff_t& coeff) +{ + coeff.clear(); + coeff.resize(sample.getNumberOfLayers()); + + calculateEigenvalues(sample, k, coeff); + + calculateTransferAndBoundary(sample, k, coeff); +} + +void SpecularMagnetic::calculateEigenvalues(const MultiLayer& sample, + const kvector_t& k, MultiLayerCoeff_t& coeff) const +{ + double mag_k = k.mag(); + for(size_t i=0; i<coeff.size(); ++i) { + coeff[i].m_scatt_matrix = sample.getLayer(i)->getMaterial()-> + getScatteringMatrix(k); + coeff[i].m_a = coeff[i].m_scatt_matrix.trace()/2.0; + coeff[i].m_b_mag = std::sqrt(coeff[i].m_a*coeff[i].m_a - + coeff[i].m_scatt_matrix.determinant()); + coeff[i].m_bz = ( coeff[i].m_scatt_matrix(0,0) - + coeff[i].m_scatt_matrix(1,1) )/2.0; + coeff[i].lambda(0) = std::sqrt(coeff[i].m_a - coeff[i].m_b_mag); + coeff[i].lambda(1) = std::sqrt(coeff[i].m_a + coeff[i].m_b_mag); + coeff[i].kz = mag_k*coeff[i].lambda; + } +} + +void SpecularMagnetic::calculateTransferAndBoundary(const MultiLayer& sample, + const kvector_t& k, MultiLayerCoeff_t& coeff) const +{ + size_t N = coeff.size(); + if (coeff[0].lambda == Eigen::Vector2cd::Zero() && N>1) { + setForNoTransmission(coeff); + return; + } + + for (int i=1; i<(int)N; ++i) { + coeff[i].calculateTRMatrices(); + double t = sample.getLayer(i)->getThickness(); + coeff[i].l = + coeff[i].R1m * getImExponential((complex_t)(coeff[i].kz(0)*t)) + + coeff[i].T1m * getImExponential((complex_t)(-coeff[i].kz(0)*t)) + + coeff[i].R2m * getImExponential((complex_t)(coeff[i].kz(1)*t)) + + coeff[i].T2m * getImExponential((complex_t)(-coeff[i].kz(1)*t)); + } +} + +Eigen::Matrix2cd SpecularMagnetic::getUnitMatrix() const +{ + return Eigen::Matrix2cd::Identity(); +} + +void SpecularMagnetic::setForNoTransmission(MultiLayerCoeff_t& coeff) const +{ + size_t N = coeff.size(); + for (size_t i=0; i<N; ++i) { + coeff[i].phi_psi.setZero(); + coeff[i].l.setIdentity(); + coeff[i].T1m = coeff[i].l/4.0; + coeff[i].R1m = coeff[i].T1m; + coeff[i].T2m = coeff[i].T1m; + coeff[i].R2m = coeff[i].T1m; + } +} + +void SpecularMagnetic::LayerMatrixCoeff::calculateTRMatrices() +{ + if (m_b_mag == 0.0) { + calculateTRWithoutMagnetization(); + return; + } + + // T1m: + // row 0: + T1m(0,0) = (1.0 - m_bz/m_b_mag)/4.0; + T1m(0,1) = - m_scatt_matrix(0,1)/4.0/m_b_mag; + T1m(0,2) = lambda(0)*(m_bz/m_b_mag - 1.0)/4.0; + T1m(0,3) = m_scatt_matrix(0,1)*lambda(0)/4.0/m_b_mag; + // row 1: + T1m(1,0) = - m_scatt_matrix(1,0)/4.0/m_b_mag; + T1m(1,1) = (1.0 + m_bz/m_b_mag)/4.0; + T1m(1,2) = m_scatt_matrix(1,0)*lambda(0)/4.0/m_b_mag; + T1m(1,3) = - lambda(0)*(m_bz/m_b_mag + 1.0)/4.0; + // row 2: + T1m(2,0) = -(1.0 - m_bz/m_b_mag)/4.0/lambda(0); + T1m(2,1) = m_scatt_matrix(0,1)/4.0/m_b_mag/lambda(0); + T1m(2,2) = -(m_bz/m_b_mag - 1.0)/4.0; + T1m(2,3) = - m_scatt_matrix(0,1)/4.0/m_b_mag; + // row 3: + T1m(3,0) = m_scatt_matrix(1,0)/4.0/m_b_mag/lambda(0); + T1m(3,1) = -(1.0 + m_bz/m_b_mag)/4.0/lambda(0); + T1m(3,2) = - m_scatt_matrix(1,0)/4.0/m_b_mag; + T1m(3,3) = (m_bz/m_b_mag + 1.0)/4.0; + + // R1m: + // row 0: + R1m(0,0) = T1m(0,0); + R1m(0,1) = T1m(0,1); + R1m(0,2) = -T1m(0,2); + R1m(0,3) = -T1m(0,3); + // row 1: + R1m(1,0) = T1m(1,0); + R1m(1,1) = T1m(1,1); + R1m(1,2) = -T1m(1,2); + R1m(1,3) = -T1m(1,3); + // row 2: + R1m(2,0) = -T1m(2,0); + R1m(2,1) = -T1m(2,1); + R1m(2,2) = T1m(2,2); + R1m(2,3) = T1m(2,3); + // row 3: + R1m(3,0) = -T1m(3,0); + R1m(3,1) = -T1m(3,1); + R1m(3,2) = T1m(3,2); + R1m(3,3) = T1m(3,3); + + // T2m: + // row 0: + T2m(0,0) = (1.0 + m_bz/m_b_mag)/4.0; + T2m(0,1) = m_scatt_matrix(0,1)/4.0/m_b_mag; + T2m(0,2) = - lambda(1)*(m_bz/m_b_mag + 1.0)/4.0; + T2m(0,3) = - m_scatt_matrix(0,1)*lambda(1)/4.0/m_b_mag; + // row 1: + T2m(1,0) = m_scatt_matrix(1,0)/4.0/m_b_mag; + T2m(1,1) = (1.0 - m_bz/m_b_mag)/4.0; + T2m(1,2) = - m_scatt_matrix(1,0)*lambda(1)/4.0/m_b_mag; + T2m(1,3) = lambda(1)*(m_bz/m_b_mag - 1.0)/4.0; + // row 2: + T2m(2,0) = -(1.0 + m_bz/m_b_mag)/4.0/lambda(1); + T2m(2,1) = - m_scatt_matrix(0,1)/4.0/m_b_mag/lambda(1); + T2m(2,2) = (m_bz/m_b_mag + 1.0)/4.0; + T2m(2,3) = m_scatt_matrix(0,1)/4.0/m_b_mag; + // row 3: + T2m(3,0) = - m_scatt_matrix(1,0)/4.0/m_b_mag/lambda(1); + T2m(3,1) = -(1.0 - m_bz/m_b_mag)/4.0/lambda(1); + T2m(3,2) = m_scatt_matrix(1,0)/4.0/m_b_mag; + T2m(3,3) = (1.0 - m_bz/m_b_mag)/4.0; + + // R2m: + // row 0: + R2m(0,0) = T2m(0,0); + R2m(0,1) = T2m(0,1); + R2m(0,2) = -T2m(0,2); + R2m(0,3) = -T2m(0,3); + // row 1: + R2m(1,0) = T2m(1,0); + R2m(1,1) = T2m(1,1); + R2m(1,2) = -T2m(1,2); + R2m(1,3) = -T2m(1,3); + // row 2: + R2m(2,0) = -T2m(2,0); + R2m(2,1) = -T2m(2,1); + R2m(2,2) = T2m(2,2); + R2m(2,3) = T2m(2,3); + // row 3: + R2m(3,0) = -T2m(3,0); + R2m(3,1) = -T2m(3,1); + R2m(3,2) = T2m(3,2); + R2m(3,3) = T2m(3,3); +} + +void SpecularMagnetic::LayerMatrixCoeff::calculateTRWithoutMagnetization() +{ + // T1m: + T1m.setZero(); + T1m(1,1) = 0.5; + T1m(1,3) = -std::sqrt(m_a)/2.0; + T1m(3,1) = -1.0/(2.0*std::sqrt(m_a)); + T1m(3,3) = 0.5; + + // R1m: + R1m.setZero(); + R1m(0,0) = 0.5; + R1m(0,2) = -std::sqrt(m_a)/2.0; + R1m(2,0) = -1.0/(2.0*std::sqrt(m_a)); + R1m(2,2) = 0.5; + + // T2m: + T2m.setZero(); + T2m(1,1) = 0.5; + T2m(1,3) = std::sqrt(m_a)/2.0; + T2m(3,1) = 1.0/(2.0*std::sqrt(m_a)); + T2m(3,3) = 0.5; + + // R2m: + R2m.setZero(); + R2m(0,0) = 0.5; + R2m(0,2) = std::sqrt(m_a)/2.0; + R2m(2,0) = 1.0/(2.0*std::sqrt(m_a)); + R2m(2,2) = 0.5; +} + +complex_t SpecularMagnetic::getImExponential(complex_t exponent) const +{ + // TODO: add over- and underflow checks! + return std::exp(complex_t(0.0, 1.0)*exponent); +} diff --git a/Core/Algorithms/src/SpecularMatrix.cpp b/Core/Algorithms/src/SpecularMatrix.cpp index de1e5eda41368e64536277a91d59ac2f8431b7b2..66cc9fbbac2b3db3c4a33ac32265d16fd1545b51 100644 --- a/Core/Algorithms/src/SpecularMatrix.cpp +++ b/Core/Algorithms/src/SpecularMatrix.cpp @@ -141,12 +141,7 @@ Eigen::Matrix2cd SpecularMatrix::calculatePMatrix(double sigma_eff, Eigen::Matrix2cd SpecularMatrix::getUnitMatrix() const { - Eigen::Matrix2cd unit; - unit(0,0) = 1.0; - unit(0,1) = 0.0; - unit(1,0) = 0.0; - unit(1,1) = 1.0; - return unit; + return Eigen::Matrix2cd::Identity(); } complex_t SpecularMatrix::getPMatrixElement(complex_t sigma_lambda) const diff --git a/Core/Core.pro b/Core/Core.pro index 7a42368f8d04203d0106ef6f88885bc8bb41f475..03cbeed7ab32716f0ee55fb487bc719ee7735524 100644 --- a/Core/Core.pro +++ b/Core/Core.pro @@ -76,6 +76,7 @@ SOURCES += \ Algorithms/src/ResolutionFunction2DSimple.cpp \ Algorithms/src/Simulation.cpp \ Algorithms/src/SizeSpacingCorrelationApproximationStrategy.cpp \ + Algorithms/src/SpecularMagnetic.cpp \ Algorithms/src/SpecularMatrix.cpp \ Algorithms/src/StrategyBuilder.cpp \ \ @@ -224,6 +225,7 @@ HEADERS += \ Algorithms/inc/Simulation.h \ Algorithms/inc/SimulationParameters.h \ Algorithms/inc/SizeSpacingCorrelationApproximationStrategy.h \ + Algorithms/inc/SpecularMagnetic.h \ Algorithms/inc/SpecularMatrix.h \ Algorithms/inc/StrategyBuilder.h \ Algorithms/inc/ThreadInfo.h \ diff --git a/Core/Samples/inc/HomogeneousMagneticMaterial.h b/Core/Samples/inc/HomogeneousMagneticMaterial.h index 7709384693629396a834f52216f60c4712b0f081..12a080449cc9ad6382b758c424abf515c5175f6b 100644 --- a/Core/Samples/inc/HomogeneousMagneticMaterial.h +++ b/Core/Samples/inc/HomogeneousMagneticMaterial.h @@ -52,7 +52,7 @@ public: //! Get the scattering matrix from the refractive index, the //! magnetic field and a given wavevector - Eigen::Matrix2cd getScatteringMatrix(const kvector_t& k) const; + virtual Eigen::Matrix2cd getScatteringMatrix(const kvector_t& k) const; protected: kvector_t m_magnetic_field; //!< magnetic field in Tesla private: diff --git a/Core/Samples/inc/HomogeneousMaterial.h b/Core/Samples/inc/HomogeneousMaterial.h index fef46754b910c15b4db9a5a9716de1f9ae326df6..db967ba946f7ccafce38e22d67a1dbd344f942f6 100644 --- a/Core/Samples/inc/HomogeneousMaterial.h +++ b/Core/Samples/inc/HomogeneousMaterial.h @@ -23,7 +23,7 @@ class HomogeneousMaterial : public IMaterial { - public: +public: //! Constructs a material with _name_ and _refractive_index_. HomogeneousMaterial(const std::string& name, const complex_t& refractive_index) @@ -47,7 +47,10 @@ class HomogeneousMaterial : public IMaterial void setRefractiveIndex(const complex_t &refractive_index) { m_refractive_index = refractive_index; } - protected: + //! Get the scattering matrix from the refractive index + //! and a given wavevector + virtual Eigen::Matrix2cd getScatteringMatrix(const kvector_t& k) const; +protected: virtual void print(std::ostream& ostr) const { ostr << "HomMat:" << getName() << "<" << this << ">{ " << @@ -57,6 +60,16 @@ class HomogeneousMaterial : public IMaterial complex_t m_refractive_index; //!< complex index of refraction }; +inline Eigen::Matrix2cd HomogeneousMaterial::getScatteringMatrix( + const kvector_t& k) const +{ + Eigen::Matrix2cd result; + double xy_proj2 = k.magxy2()/k.mag2(); + complex_t unit_factor = m_refractive_index*m_refractive_index - xy_proj2; + result = unit_factor*Eigen::Matrix2cd::Identity(); + return result; +} + #endif // HOMOGENEOUSMATERIAL_H diff --git a/Core/Samples/inc/IMaterial.h b/Core/Samples/inc/IMaterial.h index 88a1e84eb8379ce4f67967ef0202f35452aac90f..c30ac9254f4f449c14be4c3a182dfb4371a4fe3f 100644 --- a/Core/Samples/inc/IMaterial.h +++ b/Core/Samples/inc/IMaterial.h @@ -16,15 +16,18 @@ #ifndef IMATERIAL_H #define IMATERIAL_H +#include "INamed.h" +#include "Types.h" + #include <string> #include <iostream> -#include "INamed.h" +#include <Eigen/Core> //! Interface to a named material. class IMaterial : public INamed { - public: +public: //! Constructor that sets _name_. explicit IMaterial(const std::string& name) : INamed(name) {} @@ -39,7 +42,14 @@ class IMaterial : public INamed friend std::ostream &operator<<(std::ostream &ostr, const IMaterial &m) { m.print(ostr); return ostr; } - protected: + //! Get the scattering matrix from the refractive index + //! and a given wavevector + virtual Eigen::Matrix2cd getScatteringMatrix(const kvector_t& k) const { + (void)k; + return Eigen::Matrix2cd::Identity(); + } + +protected: virtual void print(std::ostream& ostr) const { ostr << "IMat:" << getName() << "<" << this << ">"; } }; diff --git a/Core/Samples/src/HomogeneousMagneticMaterial.cpp b/Core/Samples/src/HomogeneousMagneticMaterial.cpp index 14ae68748004ac47c42091a52c3d0a256e7cbd23..b2a119738d58e72d06f6523380e8c0a8b44f273a 100644 --- a/Core/Samples/src/HomogeneousMagneticMaterial.cpp +++ b/Core/Samples/src/HomogeneousMagneticMaterial.cpp @@ -41,8 +41,10 @@ Eigen::Matrix2cd HomogeneousMagneticMaterial::getScatteringMatrix( { Eigen::Matrix2cd result; double kmag = k.mag(); + double xy_proj2 = k.magxy2()/k.mag2(); double factor = m_magnetic_prefactor/kmag/kmag; - result = m_refractive_index*m_refractive_index*m_unit_matrix + complex_t unit_factor = m_refractive_index*m_refractive_index - xy_proj2; + result = unit_factor*m_unit_matrix + factor*m_pauli_operator[0]*m_magnetic_field[0] + factor*m_pauli_operator[1]*m_magnetic_field[1] + factor*m_pauli_operator[2]*m_magnetic_field[2];