diff --git a/Core/Export/SampleToPython.cpp b/Core/Export/SampleToPython.cpp index 07301b1735112f5822230d9b284648c32cbee560..3a3b544cdf005206be7fb396940b6f1431e41e36 100644 --- a/Core/Export/SampleToPython.cpp +++ b/Core/Export/SampleToPython.cpp @@ -155,10 +155,10 @@ const std::map<MATERIAL_TYPES, std::string> factory_names{ std::string SampleToPython::defineMaterials() const { const auto themap = m_materials->materialMap(); if (themap.empty()) - return "# No Materials.\n\n"; + return ""; std::ostringstream result; result << std::setprecision(12); - result << indent() << "# Define Materials\n"; + result << indent() << "# Define materials\n"; std::set<std::string> visitedMaterials; for (auto it : themap) { const std::string& key = it.first; diff --git a/Core/Legacy/MatrixRTCoefficients_v1.cpp b/Core/Legacy/MatrixRTCoefficients_v1.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f297e3ab5a23907a8d6b1f38748d87b9681448b --- /dev/null +++ b/Core/Legacy/MatrixRTCoefficients_v1.cpp @@ -0,0 +1,303 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Sample/RT/MatrixRTCoefficients_v1.cpp +//! @brief Implements class MatrixRTCoefficients_v1. +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#include "Core/Legacy/MatrixRTCoefficients_v1.h" + +MatrixRTCoefficients_v1* MatrixRTCoefficients_v1::clone() const { + return new MatrixRTCoefficients_v1(*this); +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::T1plus() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = T1m * phi_psi_plus; + result(0) = m(2); + result(1) = m(3); + if (lambda(0) == 0.0 && result == Eigen::Vector2cd::Zero()) + result(0) = 0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::R1plus() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = R1m * phi_psi_plus; + result(0) = m(2); + result(1) = m(3); + Eigen::Matrix<complex_t, 4, 1> mT = T1m * phi_psi_plus; + if (lambda(0) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) + result(0) = -0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::T2plus() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = T2m * phi_psi_plus; + result(0) = m(2); + result(1) = m(3); + if (lambda(1) == 0.0 && result == Eigen::Vector2cd::Zero()) + result(0) = 0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::R2plus() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = R2m * phi_psi_plus; + result(0) = m(2); + result(1) = m(3); + Eigen::Matrix<complex_t, 4, 1> mT = T2m * phi_psi_plus; + if (lambda(1) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) + result(0) = -0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::T1min() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = T1m * phi_psi_min; + result(0) = m(2); + result(1) = m(3); + if (lambda(0) == 0.0 && result == Eigen::Vector2cd::Zero()) + result(1) = 0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::R1min() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = R1m * phi_psi_min; + result(0) = m(2); + result(1) = m(3); + Eigen::Matrix<complex_t, 4, 1> mT = T1m * phi_psi_min; + if (lambda(0) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) + result(1) = -0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::T2min() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = T2m * phi_psi_min; + result(0) = m(2); + result(1) = m(3); + if (lambda(1) == 0.0 && result == Eigen::Vector2cd::Zero()) + result(1) = 0.5; + return result; +} + +Eigen::Vector2cd MatrixRTCoefficients_v1::R2min() const { + Eigen::Vector2cd result; + Eigen::Matrix<complex_t, 4, 1> m = R2m * phi_psi_min; + result(0) = m(2); + result(1) = m(3); + Eigen::Matrix<complex_t, 4, 1> mT = T2m * phi_psi_min; + if (lambda(1) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) + result(1) = -0.5; + return result; +} + +void MatrixRTCoefficients_v1::calculateTRMatrices() { + if (m_b_mag == 0.0) { + calculateTRWithoutMagnetization(); + return; + } + + if (lambda(0) == 0.0) { + complex_t ikt = mul_I(m_kt); + // Lambda1 component contained only in T1m (R1m=0) + // row 0: + T1m(0, 0) = (1.0 - m_bz / m_b_mag) / 2.0; + T1m(0, 1) = -m_scatt_matrix(0, 1) / 2.0 / m_b_mag; + // row 1: + T1m(1, 0) = -m_scatt_matrix(1, 0) / 2.0 / m_b_mag; + T1m(1, 1) = (1.0 + m_bz / m_b_mag) / 2.0; + // row 2: + T1m(2, 0) = ikt * (1.0 - m_bz / m_b_mag) / 2.0; + T1m(2, 1) = -ikt * m_scatt_matrix(0, 1) / 2.0 / m_b_mag; + T1m(2, 2) = T1m(0, 0); + T1m(2, 3) = T1m(0, 1); + // row 3: + T1m(3, 0) = -ikt * m_scatt_matrix(1, 0) / 2.0 / m_b_mag; + T1m(3, 1) = ikt * (1.0 + m_bz / m_b_mag) / 2.0; + T1m(3, 2) = T1m(1, 0); + T1m(3, 3) = T1m(1, 1); + } else { + // 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); + } + + if (lambda(1) == 0.0) { + complex_t ikt = mul_I(m_kt); + // Lambda2 component contained only in T2m (R2m=0) + // row 0: + T2m(0, 0) = (1.0 + m_bz / m_b_mag) / 2.0; + T2m(0, 1) = m_scatt_matrix(0, 1) / 2.0 / m_b_mag; + // row 1: + T2m(1, 0) = m_scatt_matrix(1, 0) / 2.0 / m_b_mag; + T2m(1, 1) = (1.0 - m_bz / m_b_mag) / 2.0; + // row 2: + T2m(2, 0) = ikt * (1.0 + m_bz / m_b_mag) / 2.0; + T2m(2, 1) = ikt * m_scatt_matrix(0, 1) / 2.0 / m_b_mag; + T2m(2, 2) = T2m(0, 0); + T2m(2, 3) = T2m(0, 1); + // row 3: + T2m(3, 0) = ikt * m_scatt_matrix(1, 0) / 2.0 / m_b_mag; + T2m(3, 1) = ikt * (1.0 - m_bz / m_b_mag) / 2.0; + T2m(3, 2) = T2m(1, 0); + T2m(3, 3) = T2m(1, 1); + } else { + // 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 MatrixRTCoefficients_v1::calculateTRWithoutMagnetization() { + T1m.setZero(); + R1m.setZero(); + T2m.setZero(); + R2m.setZero(); + + if (m_a == 0.0) { + // Spin down component contained only in T1 (R1=0) + T1m(1, 1) = 1.0; + T1m(3, 1) = mul_I(m_kt); + T1m(3, 3) = 1.0; + + // Spin up component contained only in T2 (R2=0) + T2m(0, 0) = 1.0; + T2m(2, 0) = mul_I(m_kt); + T2m(2, 2) = 1.0; + return; + } + + // T1m: + 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(1, 1) = 0.5; + R1m(1, 3) = std::sqrt(m_a) / 2.0; + R1m(3, 1) = 1.0 / (2.0 * std::sqrt(m_a)); + R1m(3, 3) = 0.5; + + // T2m: + T2m(0, 0) = 0.5; + T2m(0, 2) = -std::sqrt(m_a) / 2.0; + T2m(2, 0) = -1.0 / (2.0 * std::sqrt(m_a)); + T2m(2, 2) = 0.5; + + // R2m: + 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; +} + +void MatrixRTCoefficients_v1::initializeBottomLayerPhiPsi() { + if (m_b_mag == 0.0) { + phi_psi_min << 0.0, -std::sqrt(m_a), 0.0, 1.0; + phi_psi_plus << -std::sqrt(m_a), 0.0, 1.0, 0.0; + return; + } + // First basis vector that has no upward going wave amplitude + phi_psi_min(0) = m_scatt_matrix(0, 1) * (lambda(0) - lambda(1)) / 2.0 / m_b_mag; + phi_psi_min(1) = (m_bz * (lambda(1) - lambda(0)) / m_b_mag - lambda(1) - lambda(0)) / 2.0; + phi_psi_min(2) = 0.0; + phi_psi_min(3) = 1.0; + + // Second basis vector that has no upward going wave amplitude + phi_psi_plus(0) = -(m_scatt_matrix(0, 0) + lambda(0) * lambda(1)) / (lambda(0) + lambda(1)); + phi_psi_plus(1) = m_scatt_matrix(1, 0) * (lambda(0) - lambda(1)) / 2.0 / m_b_mag; + phi_psi_plus(2) = 1.0; + phi_psi_plus(3) = 0.0; +} diff --git a/Core/Legacy/MatrixRTCoefficients_v1.h b/Core/Legacy/MatrixRTCoefficients_v1.h new file mode 100644 index 0000000000000000000000000000000000000000..b983370cc21c5a9af1b90af76132cf3de7db5f6e --- /dev/null +++ b/Core/Legacy/MatrixRTCoefficients_v1.h @@ -0,0 +1,69 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Sample/RT/MatrixRTCoefficients_v1.h +//! @brief Defines class MatrixRTCoefficients_v1. +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#ifndef BORNAGAIN_CORE_LEGACY_MATRIXRTCOEFFICIENTS_V1_H +#define BORNAGAIN_CORE_LEGACY_MATRIXRTCOEFFICIENTS_V1_H + +#include "Sample/RT/ILayerRTCoefficients.h" + +//! Specular reflection and transmission coefficients in a layer in case +//! of 2x2 matrix interactions between the layers and the scattered particle. +//! @ingroup algorithms_internal + +class MatrixRTCoefficients_v1 : public ILayerRTCoefficients { +public: + MatrixRTCoefficients_v1() : m_kt(0.0) {} + virtual ~MatrixRTCoefficients_v1() {} + + virtual MatrixRTCoefficients_v1* clone() const; + + //! The following functions return the transmitted and reflected amplitudes + //! for different incoming beam polarizations and eigenmodes + virtual Eigen::Vector2cd T1plus() const; + virtual Eigen::Vector2cd R1plus() const; + virtual Eigen::Vector2cd T2plus() const; + virtual Eigen::Vector2cd R2plus() const; + virtual Eigen::Vector2cd T1min() const; + virtual Eigen::Vector2cd R1min() const; + virtual Eigen::Vector2cd T2min() const; + virtual Eigen::Vector2cd R2min() const; + //! Returns z-part of the two wavevector eigenmodes + virtual Eigen::Vector2cd getKz() const { return kz; } + + void calculateTRMatrices(); + void calculateTRWithoutMagnetization(); + void initializeBottomLayerPhiPsi(); + + // NOTE: exceptionally, this class has member variables without prefix m_ + Eigen::Vector2cd kz; //!< z-part of the two wavevector eigenmodes + Eigen::Vector2cd lambda; //!< positive eigenvalues of transfer matrix + Eigen::Vector4cd phi_psi_plus; //!< boundary values for up-polarization + Eigen::Vector4cd phi_psi_min; //!< boundary values for down-polarization + Eigen::Matrix4cd T1m; //!< matrix selecting the transmitted part of + //!< the first eigenmode + Eigen::Matrix4cd R1m; //!< matrix selecting the reflected part of + //!< the first eigenmode + Eigen::Matrix4cd T2m; //!< matrix selecting the transmitted part of + //!< the second eigenmode + Eigen::Matrix4cd R2m; //!< matrix selecting the reflected part of + //!< the second eigenmode + Eigen::Matrix2cd m_scatt_matrix; //!< scattering matrix + complex_t m_a; //!< polarization independent part of scattering matrix + complex_t m_b_mag; //!< magnitude of magnetic interaction term + complex_t m_bz; //!< z-part of magnetic interaction term + double m_kt; //!< wavevector length times thickness of layer for use when + //!< lambda=0 +}; + +#endif // BORNAGAIN_CORE_LEGACY_MATRIXRTCOEFFICIENTS_V1_H diff --git a/Sample/RT/MatrixRTCoefficients_v2.cpp b/Core/Legacy/MatrixRTCoefficients_v2.cpp similarity index 98% rename from Sample/RT/MatrixRTCoefficients_v2.cpp rename to Core/Legacy/MatrixRTCoefficients_v2.cpp index f976fcf69574ab1080f53797fa7b06d305a1a799..24f23b5b5a74384c7885b86197784022a164dd5d 100644 --- a/Sample/RT/MatrixRTCoefficients_v2.cpp +++ b/Core/Legacy/MatrixRTCoefficients_v2.cpp @@ -12,7 +12,7 @@ // // ************************************************************************************************ -#include "Sample/RT/MatrixRTCoefficients_v2.h" +#include "Core/Legacy/MatrixRTCoefficients_v2.h" namespace { Eigen::Vector2cd waveVector(const Eigen::Matrix4cd& frob_matrix, diff --git a/Sample/RT/MatrixRTCoefficients_v2.h b/Core/Legacy/MatrixRTCoefficients_v2.h similarity index 91% rename from Sample/RT/MatrixRTCoefficients_v2.h rename to Core/Legacy/MatrixRTCoefficients_v2.h index dfdc242bcb1830d9ebb902242f15733711ae11dd..2146ea36eace9cd1286c4a082df35c47f4321412 100644 --- a/Sample/RT/MatrixRTCoefficients_v2.h +++ b/Core/Legacy/MatrixRTCoefficients_v2.h @@ -12,8 +12,8 @@ // // ************************************************************************************************ -#ifndef BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_V2_H -#define BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_V2_H +#ifndef BORNAGAIN_CORE_LEGACY_MATRIXRTCOEFFICIENTS_V2_H +#define BORNAGAIN_CORE_LEGACY_MATRIXRTCOEFFICIENTS_V2_H #include "Base/Vector/Vectors3D.h" #include "Sample/RT/ILayerRTCoefficients.h" @@ -25,7 +25,8 @@ class MatrixRTCoefficients_v2 : public ILayerRTCoefficients { public: - friend class SpecularMagneticStrategy; + friend class SpecularMagneticStrategy_v2; + friend class SpecularMagneticOriginalStrategy; MatrixRTCoefficients_v2(double kz_sign, Eigen::Vector2cd eigenvalues, kvector_t b); MatrixRTCoefficients_v2(const MatrixRTCoefficients_v2& other); @@ -66,4 +67,4 @@ private: //!< the second eigenmode }; -#endif // BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_V2_H +#endif // BORNAGAIN_CORE_LEGACY_MATRIXRTCOEFFICIENTS_V2_H diff --git a/Sample/Specular/SpecularMagneticOldStrategy.cpp b/Core/Legacy/SpecularMagneticStrategy_v1.cpp similarity index 89% rename from Sample/Specular/SpecularMagneticOldStrategy.cpp rename to Core/Legacy/SpecularMagneticStrategy_v1.cpp index 601711f3c4f788dfa5f7ecf4fd5f2ca662edd824..0171d494e2be2c5d7b975a08aaf21f2e530155ac 100644 --- a/Sample/Specular/SpecularMagneticOldStrategy.cpp +++ b/Core/Legacy/SpecularMagneticStrategy_v1.cpp @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/Specular/SpecularMagneticOldStrategy.cpp -//! @brief Implements class SpecularMagneticOldStrategy. +//! @file Sample/Specular/SpecularMagneticStrategy_v1.cpp +//! @brief Implements class SpecularMagneticStrategy_v1. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,7 +12,7 @@ // // ************************************************************************************************ -#include "Sample/Specular/SpecularMagneticOldStrategy.h" +#include "SpecularMagneticStrategy_v1.h" #include "Sample/Material/WavevectorInfo.h" #include "Sample/Multilayer/Layer.h" #include "Sample/Multilayer/MultiLayer.h" @@ -22,35 +22,35 @@ namespace { void CalculateEigenvalues(const std::vector<Slice>& slices, const kvector_t k, - std::vector<MatrixRTCoefficients>& coeff); + std::vector<MatrixRTCoefficients_v1>& coeff); void CalculateTransferAndBoundary(const std::vector<Slice>& slices, - std::vector<MatrixRTCoefficients>& coeff); -void SetForNoTransmission(std::vector<MatrixRTCoefficients>& coeff); + std::vector<MatrixRTCoefficients_v1>& coeff); +void SetForNoTransmission(std::vector<MatrixRTCoefficients_v1>& coeff); complex_t GetImExponential(complex_t exponent); } // namespace -ISpecularStrategy::coeffs_t SpecularMagneticOldStrategy::Execute(const std::vector<Slice>& slices, +ISpecularStrategy::coeffs_t SpecularMagneticStrategy_v1::Execute(const std::vector<Slice>& slices, const kvector_t& k) const { - std::vector<MatrixRTCoefficients> result(slices.size()); + std::vector<MatrixRTCoefficients_v1> result(slices.size()); CalculateEigenvalues(slices, k, result); CalculateTransferAndBoundary(slices, result); - coeffs_t resultConvert; + ISpecularStrategy::coeffs_t resultConvert; for (auto& coeff : result) - resultConvert.push_back(std::make_unique<MatrixRTCoefficients>(coeff)); + resultConvert.push_back(std::make_unique<MatrixRTCoefficients_v1>(coeff)); return resultConvert; } ISpecularStrategy::coeffs_t -SpecularMagneticOldStrategy::Execute(const std::vector<Slice>&, +SpecularMagneticStrategy_v1::Execute(const std::vector<Slice>&, const std::vector<complex_t>&) const { throw std::runtime_error("Not implemented"); } namespace { void CalculateEigenvalues(const std::vector<Slice>& slices, const kvector_t k, - std::vector<MatrixRTCoefficients>& coeff) { + std::vector<MatrixRTCoefficients_v1>& coeff) { double mag_k = k.mag(); double n_ref = slices[0].material().refractiveIndex(2 * M_PI / mag_k).real(); double sign_kz = k.z() > 0.0 ? -1.0 : 1.0; @@ -78,7 +78,7 @@ void CalculateEigenvalues(const std::vector<Slice>& slices, const kvector_t k, // todo: avoid overflows (see SpecularMatrix.cpp) void CalculateTransferAndBoundary(const std::vector<Slice>& slices, - std::vector<MatrixRTCoefficients>& coeff) { + std::vector<MatrixRTCoefficients_v1>& coeff) { size_t N = coeff.size(); if (coeff[0].lambda == Eigen::Vector2cd::Zero() && N > 1) { SetForNoTransmission(coeff); @@ -136,7 +136,7 @@ void CalculateTransferAndBoundary(const std::vector<Slice>& slices, } } -void SetForNoTransmission(std::vector<MatrixRTCoefficients>& coeff) { +void SetForNoTransmission(std::vector<MatrixRTCoefficients_v1>& coeff) { size_t N = coeff.size(); for (size_t i = 0; i < N; ++i) { coeff[i].phi_psi_plus.setZero(); diff --git a/Core/Legacy/SpecularMagneticStrategy_v1.h b/Core/Legacy/SpecularMagneticStrategy_v1.h new file mode 100644 index 0000000000000000000000000000000000000000..ea99ca97e451e62fae64b4558bc576ea326ddc70 --- /dev/null +++ b/Core/Legacy/SpecularMagneticStrategy_v1.h @@ -0,0 +1,47 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Sample/Specular/SpecularMagneticStrategy_v1.h +//! @brief Defines class SpecularMagneticStrategy_v1. +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#ifndef BORNAGAIN_CORE_LEGACY_SPECULARMAGNETICSTRATEGY_V1_H +#define BORNAGAIN_CORE_LEGACY_SPECULARMAGNETICSTRATEGY_V1_H + +#include "MatrixRTCoefficients_v1.h" +#include "Sample/Specular/ISpecularStrategy.h" +#include <memory> +#include <vector> + +class Slice; + +//! Implements the matrix formalism for the calculation of wave amplitudes of +//! the coherent wave solution in a multilayer with magnetization. +//! @ingroup algorithms_internal + +class SpecularMagneticStrategy_v1 : public ISpecularStrategy { +public: + // TODO remove once external test code is not needed anmyore + // for the moment i need them! + using coefficient_type = MatrixRTCoefficients_v1; + using coefficient_pointer_type = std::unique_ptr<const coefficient_type>; + using coeffs_t = std::vector<coefficient_pointer_type>; + + //! Computes refraction angle reflection/transmission coefficients + //! for given sliced multilayer and wavevector k + ISpecularStrategy::coeffs_t Execute(const std::vector<Slice>& slices, + const kvector_t& k) const; + + ISpecularStrategy::coeffs_t Execute(const std::vector<Slice>& slices, + const std::vector<complex_t>& kz) const; + +}; // class SpecularMagneticStrategy_v1 + +#endif // BORNAGAIN_CORE_LEGACY_SPECULARMAGNETICSTRATEGY_V1_H diff --git a/Core/Legacy/SpecularMagneticStrategy_v2.cpp b/Core/Legacy/SpecularMagneticStrategy_v2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58cc59474368d4f9095bd697be1d4b94c2181182 --- /dev/null +++ b/Core/Legacy/SpecularMagneticStrategy_v2.cpp @@ -0,0 +1,273 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Sample/Specular/SpecularMagneticStrategy_v2.cpp +//! @brief Implements class SpecularMagneticStrategy_v2. +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#include "SpecularMagneticStrategy_v2.h" +#include "Base/Const/PhysicalConstants.h" +#include "Sample/Slice/KzComputation.h" +#include "Sample/Slice/Slice.h" + +namespace { +kvector_t magneticImpact(kvector_t B_field); +Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag); +Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs); +complex_t GetImExponential(complex_t exponent); + +// The factor 1e-18 is here to have unit: 1/T*nm^-2 +constexpr double magnetic_prefactor = PhysConsts::m_n * PhysConsts::g_factor_n * PhysConsts::mu_N + / PhysConsts::h_bar / PhysConsts::h_bar * 1e-18; +} // namespace + +ISpecularStrategy::coeffs_t SpecularMagneticStrategy_v2::Execute(const std::vector<Slice>& slices, + const kvector_t& k) const { + return Execute(slices, KzComputation::computeReducedKz(slices, k)); +} + +ISpecularStrategy::coeffs_t +SpecularMagneticStrategy_v2::Execute(const std::vector<Slice>& slices, + const std::vector<complex_t>& kz) const { + if (slices.size() != kz.size()) + throw std::runtime_error("Number of slices does not match the size of the kz-vector"); + + ISpecularStrategy::coeffs_t result; + for (auto& coeff : computeTR(slices, kz)) + result.push_back(std::make_unique<MatrixRTCoefficients_v2>(coeff)); + + return result; +} + +std::vector<MatrixRTCoefficients_v2> +SpecularMagneticStrategy_v2::computeTR(const std::vector<Slice>& slices, + const std::vector<complex_t>& kzs) { + if (kzs[0] == 0.) + throw std::runtime_error("Edge case k_z = 0 not implemented"); + + if (slices.size() != kzs.size()) + throw std::runtime_error( + "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside."); + if (slices.empty()) + return {}; + + std::vector<MatrixRTCoefficients_v2> result; + result.reserve(slices.size()); + + const double kz_sign = kzs.front().real() > 0.0 ? 1.0 : -1.0; // save sign to restore it later + const kvector_t b_0 = magneticImpact(slices.front().bField()); + result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0}); + for (size_t i = 1, size = slices.size(); i < size; ++i) { + kvector_t b = magneticImpact(slices[i].bField()) - b_0; + result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], b.mag())), b); + } + + if (result.front().m_lambda == Eigen::Vector2cd::Zero()) { + std::for_each(result.begin(), result.end(), [](auto& coeff) { setNoTransmission(coeff); }); + return result; + } + + std::for_each(result.begin(), result.end(), [](auto& coeff) { calculateTR(coeff); }); + nullifyBottomReflection(result.back()); + propagateBackwardsForwards(result, slices); + + return result; +} + +void SpecularMagneticStrategy_v2::calculateTR(MatrixRTCoefficients_v2& coeff) { + const double b = coeff.m_b.mag(); + if (b == 0.0) { + calculateZeroFieldTR(coeff); + return; + } + + const double bpbz = b + coeff.m_b.z(); + const double bmbz = b - coeff.m_b.z(); + const complex_t bxmby = coeff.m_b.x() - I * coeff.m_b.y(); + const complex_t bxpby = coeff.m_b.x() + I * coeff.m_b.y(); + const complex_t l_1 = coeff.m_lambda(0); + const complex_t l_2 = coeff.m_lambda(1); + + auto& T1 = coeff.T1; + T1 << bmbz, -bxmby, -bmbz * l_1, bxmby * l_1, -bxpby, bpbz, bxpby * l_1, -bpbz * l_1, + -bmbz / l_1, bxmby / l_1, bmbz, -bxmby, bxpby / l_1, -bpbz / l_1, -bxpby, bpbz; + T1 /= 4.0 * b; + + auto& R1 = coeff.R1; + 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), + -T1(2, 0), -T1(2, 1), T1(2, 2), T1(2, 3), -T1(3, 0), -T1(3, 1), T1(3, 2), T1(3, 3); + + auto& T2 = coeff.T2; + T2 << bpbz, bxmby, -bpbz * l_2, -bxmby * l_2, bxpby, bmbz, -bxpby * l_2, -bmbz * l_2, + -bpbz / l_2, -bxmby / l_2, bpbz, bxmby, -bxpby / l_2, -bmbz / l_2, bxpby, bmbz; + T2 /= 4.0 * b; + + auto& R2 = coeff.R2; + 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), + -T2(2, 0), -T2(2, 1), T2(2, 2), T2(2, 3), -T2(3, 0), -T2(3, 1), T2(3, 2), T2(3, 3); +} + +void SpecularMagneticStrategy_v2::calculateZeroFieldTR(MatrixRTCoefficients_v2& coeff) { + coeff.T1 = Eigen::Matrix4cd::Zero(); + coeff.R1 = Eigen::Matrix4cd::Zero(); + coeff.T2 = Eigen::Matrix4cd::Zero(); + coeff.R2 = Eigen::Matrix4cd::Zero(); + + // lambda_1 == lambda_2, no difference which one to use + const complex_t eigen_value = coeff.m_lambda(0); + + Eigen::Matrix3cd Tblock; + Tblock << 0.5, 0.0, -0.5 * eigen_value, 0.0, 0.0, 0.0, -0.5 / eigen_value, 0.0, 0.5; + + Eigen::Matrix3cd Rblock; + Rblock << 0.5, 0.0, 0.5 * eigen_value, 0.0, 0.0, 0.0, 0.5 / eigen_value, 0.0, 0.5; + + coeff.T1.block<3, 3>(1, 1) = Tblock; + coeff.R1.block<3, 3>(1, 1) = Rblock; + coeff.T2.block<3, 3>(0, 0) = Tblock; + coeff.R2.block<3, 3>(0, 0) = Rblock; +} + +void SpecularMagneticStrategy_v2::setNoTransmission(MatrixRTCoefficients_v2& coeff) { + coeff.m_w_plus = Eigen::Vector4cd::Zero(); + coeff.m_w_min = Eigen::Vector4cd::Zero(); + coeff.T1 = Eigen::Matrix4cd::Identity() / 4.0; + coeff.R1 = coeff.T1; + coeff.T2 = coeff.T1; + coeff.R2 = coeff.T1; +} + +void SpecularMagneticStrategy_v2::nullifyBottomReflection(MatrixRTCoefficients_v2& coeff) { + const complex_t l_1 = coeff.m_lambda(0); + const complex_t l_2 = coeff.m_lambda(1); + const double b_mag = coeff.m_b.mag(); + const kvector_t& b = coeff.m_b; + + if (b_mag == 0.0) { + // both eigenvalues are the same, no difference which one to take + coeff.m_w_plus << -l_1, 0.0, 1.0, 0.0; + coeff.m_w_min << 0.0, -l_1, 0.0, 1.0; + return; + } + + // First basis vector that has no upward going wave amplitude + coeff.m_w_min(0) = (b.x() - I * b.y()) * (l_1 - l_2) / 2.0 / b_mag; + coeff.m_w_min(1) = b.z() * (l_2 - l_1) / 2.0 / b_mag - (l_1 + l_2) / 2.0; + coeff.m_w_min(2) = 0.0; + coeff.m_w_min(3) = 1.0; + + // Second basis vector that has no upward going wave amplitude + coeff.m_w_plus(0) = -(l_1 + l_2) / 2.0 - b.z() / (l_1 + l_2); + coeff.m_w_plus(1) = (b.x() + I * b.y()) * (l_1 - l_2) / 2.0 / b_mag; + coeff.m_w_plus(2) = 1.0; + coeff.m_w_plus(3) = 0.0; +} + +void SpecularMagneticStrategy_v2::propagateBackwardsForwards( + std::vector<MatrixRTCoefficients_v2>& coeff, const std::vector<Slice>& slices) { + const int size = static_cast<int>(coeff.size()); + std::vector<Eigen::Matrix2cd> SMatrices(coeff.size()); + std::vector<complex_t> Normalization(coeff.size()); + + for (int index = size - 2; index >= 0; --index) { + const size_t i = static_cast<size_t>(index); + const double t = slices[i].thickness(); + const auto kz = coeff[i].getKz(); + const Eigen::Matrix4cd l = coeff[i].R1 * GetImExponential(kz(0) * t) + + coeff[i].T1 * GetImExponential(-kz(0) * t) + + coeff[i].R2 * GetImExponential(kz(1) * t) + + coeff[i].T2 * GetImExponential(-kz(1) * t); + coeff[i].m_w_plus = l * coeff[i + 1].m_w_plus; + coeff[i].m_w_min = l * coeff[i + 1].m_w_min; + + // rotate and normalize polarization + const auto Snorm = findNormalizationCoefficients(coeff[i]); + auto S = Snorm.first; + auto norm = Snorm.second; + + SMatrices[i] = S; + Normalization[i] = norm; + + const complex_t a_plus = S(0, 0) / norm; + const complex_t b_plus = S(1, 0) / norm; + const complex_t a_min = S(0, 1) / norm; + const complex_t b_min = S(1, 1) / norm; + + const Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min; + const Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min; + + coeff[i].m_w_plus = std::move(w_plus); + coeff[i].m_w_min = std::move(w_min); + } + + complex_t dumpingFactor = 1; + Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity(); + for (size_t i = 1; i < coeff.size(); ++i) { + dumpingFactor = dumpingFactor * Normalization[i - 1]; + S = SMatrices[i - 1] * S; + + if (std::isinf(std::norm(dumpingFactor))) { + // not entirely sure, whether this is the correct edge case + std::for_each(coeff.begin() + i, coeff.end(), + [](auto& coeff) { setNoTransmission(coeff); }); + break; + } + + const complex_t a_plus = S(0, 0) / dumpingFactor; + const complex_t b_plus = S(1, 0) / dumpingFactor; + const complex_t a_min = S(0, 1) / dumpingFactor; + const complex_t b_min = S(1, 1) / dumpingFactor; + + Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min; + Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min; + + coeff[i].m_w_plus = std::move(w_plus); + coeff[i].m_w_min = std::move(w_min); + } +} + +std::pair<Eigen::Matrix2cd, complex_t> +SpecularMagneticStrategy_v2::findNormalizationCoefficients(const MatrixRTCoefficients_v2& coeff) { + const Eigen::Vector2cd Ta = coeff.T1plus() + coeff.T2plus(); + const Eigen::Vector2cd Tb = coeff.T1min() + coeff.T2min(); + + Eigen::Matrix2cd S; + S << Ta(0), Tb(0), Ta(1), Tb(1); + + Eigen::Matrix2cd SInverse; + SInverse << S(1, 1), -S(0, 1), -S(1, 0), S(0, 0); + const complex_t d1 = S(1, 1) - S(0, 1); + const complex_t d2 = S(1, 0) - S(0, 0); + const complex_t denominator = S(0, 0) * d1 - d2 * S(0, 1); + + return {SInverse, denominator}; +} + +namespace { +kvector_t magneticImpact(kvector_t B_field) { + return -magnetic_prefactor * B_field; +} + +Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag) { + const complex_t a = kz * kz; + return {I * std::sqrt(a + b_mag), I * std::sqrt(a - b_mag)}; +} + +Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs) { + auto lambda = [](complex_t value) { return std::abs(value) < 1e-40 ? 1e-40 : value; }; + return {lambda(eigenvs(0)), lambda(eigenvs(1))}; +} + +complex_t GetImExponential(complex_t exponent) { + if (exponent.imag() > -std::log(std::numeric_limits<double>::min())) + return 0.0; + return std::exp(I * exponent); +} +} // namespace diff --git a/Core/Legacy/SpecularMagneticStrategy_v2.h b/Core/Legacy/SpecularMagneticStrategy_v2.h new file mode 100644 index 0000000000000000000000000000000000000000..1de56608eabc4df319e9f01513d2c2bd5234e287 --- /dev/null +++ b/Core/Legacy/SpecularMagneticStrategy_v2.h @@ -0,0 +1,77 @@ +// ************************************************************************************************ +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file Sample/Specular/SpecularMagneticStrategy_v2.h +//! @brief Defines class SpecularMagneticStrategy_v2. +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************************************ + +#ifndef BORNAGAIN_CORE_LEGACY_SPECULARMAGNETICSTRATEGY_V2_H +#define BORNAGAIN_CORE_LEGACY_SPECULARMAGNETICSTRATEGY_V2_H + +#include "MatrixRTCoefficients_v2.h" +#include "Sample/Specular/ISpecularStrategy.h" +#include <memory> +#include <vector> + +class Slice; + +//! Implements the magnetic Fresnel computation without roughness +//! +//! Implements the matrix formalism for the calculation of wave amplitudes of +//! the coherent wave solution in a multilayer with magnetization. +//! For a detailed description see internal document "Polarized Specular Reflectometry" +//! +//! @ingroup algorithms_internal +class SpecularMagneticStrategy_v2 : public ISpecularStrategy { +public: + // TODO remove once external test code is not needed anmyore + // for the moment i need them! + using coefficient_type = MatrixRTCoefficients_v2; + using coefficient_pointer_type = std::unique_ptr<const coefficient_type>; + using coeffs_t = std::vector<coefficient_pointer_type>; + + //! Computes refraction angle reflection/transmission coefficients + //! for given sliced multilayer and wavevector k + 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 a set of kz projections corresponding to each slice + ISpecularStrategy::coeffs_t Execute(const std::vector<Slice>& slices, + const std::vector<complex_t>& kz) const; + +private: + static std::vector<MatrixRTCoefficients_v2> computeTR(const std::vector<Slice>& slices, + const std::vector<complex_t>& kzs); + + //! Computes frobenius matrices for multilayer solution + static void calculateTR(MatrixRTCoefficients_v2& coeff); + static void calculateZeroFieldTR(MatrixRTCoefficients_v2& coeff); + + static void setNoTransmission(MatrixRTCoefficients_v2& coeff); + + //! initializes reflectionless bottom boundary condition. + static void nullifyBottomReflection(MatrixRTCoefficients_v2& coeff); + + //! Propagates boundary conditions from the bottom to the top of the layer stack. + //! Used to compute boundary conditions from the bottom one (with nullified reflection) + //! simultaneously propagates amplitudes forward again + //! Due to the use of temporary objects this is combined into one function now + static void propagateBackwardsForwards(std::vector<MatrixRTCoefficients_v2>& coeff, + const std::vector<Slice>& slices); + + //! finds linear coefficients for normalizing transmitted wave to unity. + //! The left column of the returned matrix corresponds to the coefficients for pure spin-up + //! wave, while the right column - to the coefficients for the spin-down one. + static std::pair<Eigen::Matrix2cd, complex_t> + findNormalizationCoefficients(const MatrixRTCoefficients_v2& coeff); +}; + +#endif // BORNAGAIN_CORE_LEGACY_SPECULARMAGNETICSTRATEGY_V2_H diff --git a/Examples/Python/sim01_Particles/CylindersAndPrisms.py b/Examples/Python/sim01_Particles/CylindersAndPrisms.py index 12b91c1c085e607d189d54d251f9a0e745e40171..cbab1b3b6d47c381c6f2adc6dc66d69f608dbf28 100644 --- a/Examples/Python/sim01_Particles/CylindersAndPrisms.py +++ b/Examples/Python/sim01_Particles/CylindersAndPrisms.py @@ -2,38 +2,49 @@ Mixture of cylinders and prisms without interference """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with uncorrelated cylinders and prisms on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - prism_ff = ba.FormFactorPrism3(10*nm, 5*nm) - prism = ba.Particle(m_particle, prism_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 0.5) - particle_layout.addParticle(prism, 0.5) - interference = ba.InterferenceFunctionNone() - particle_layout.setInterferenceFunction(interference) - - # vacuum layer with particles and substrate form multi layer - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorPrism3(10.0*nm, 5.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + + # Define interference functions + iff = ba.InterferenceFunctionNone() + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_1, 0.5) + layout.addParticle(particle_2, 0.5) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim01_Particles/CylindersInBA.py b/Examples/Python/sim01_Particles/CylindersInBA.py index 69e2e08e03e4859478dd1189c4d2b0c96a0dc3ee..26855e44a93ba0f63acf6bb3e266b453afc3050d 100644 --- a/Examples/Python/sim01_Particles/CylindersInBA.py +++ b/Examples/Python/sim01_Particles/CylindersInBA.py @@ -2,7 +2,7 @@ Cylinder form factor in Born approximation """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,22 +10,32 @@ def get_sample(): Returns a sample with cylinders in a homogeneous environment ("Vacuum"), implying a simulation in plain Born approximation. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer = ba.Layer(material_Vacuum) + layer.addLayout(layout) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer) + + return sample def get_simulation(): diff --git a/Examples/Python/sim01_Particles/CylindersInDWBA.py b/Examples/Python/sim01_Particles/CylindersInDWBA.py index 2d60be5dd1a91c96c073bec41a57a67a417c95fa..28d884bf62df1e399244fdd48aba86bc76b148d0 100644 --- a/Examples/Python/sim01_Particles/CylindersInDWBA.py +++ b/Examples/Python/sim01_Particles/CylindersInDWBA.py @@ -2,32 +2,42 @@ Cylinder form factor in DWBA """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim01_Particles/CylindersWithSizeDistribution.py b/Examples/Python/sim01_Particles/CylindersWithSizeDistribution.py index a5dfd5d20c4d7568dee0a3cc38741b78b6bf6066..adc1fd1decbcae25800c687551080346903e08d2 100644 --- a/Examples/Python/sim01_Particles/CylindersWithSizeDistribution.py +++ b/Examples/Python/sim01_Particles/CylindersWithSizeDistribution.py @@ -2,7 +2,7 @@ Cylinders with size distribution """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,38 +10,38 @@ def get_sample(): Return a sample with cylinders on a substrate. The cylinders have a Gaussian size distribution. """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # cylindrical particle - radius = 5*nm - height = radius - cylinder_ff = ba.FormFactorCylinder(radius, height) - cylinder = ba.Particle(m_particle, cylinder_ff) - - # collection of particles with size distribution - nparticles = 100 - sigma = 0.2*radius - - gauss_distr = ba.DistributionGaussian(radius, sigma) - - sigma_factor = 2.0 - par_distr = ba.ParameterDistribution("/Particle/Cylinder/Radius", - gauss_distr, nparticles, sigma_factor) - # by uncommenting the line below, the height of the cylinders - # can be scaled proportionally to the radius: - # par_distr.linkParameter("/Particle/Cylinder/Height") - part_coll = ba.ParticleDistribution(cylinder, par_distr) - - # assembling the sample - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(part_coll) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particles with parameter following a distribution + distr_1 = ba.DistributionGaussian(5.0*nm, 1.0*nm) + par_distr_1 = ba.ParameterDistribution("/Particle/Cylinder/Radius", distr_1, + 100, 2.0) + particle_distrib = ba.ParticleDistribution(particle, par_distr_1) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_distrib, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer = ba.Layer(material_Vacuum) + layer.addLayout(layout) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer) + + return sample def get_simulation(): diff --git a/Examples/Python/sim01_Particles/RotatedPyramids.py b/Examples/Python/sim01_Particles/RotatedPyramids.py index 4b8f260c3c685cf9d3e5eae9e7c3b7bd77dc4997..0077becb7bfe0fbb2de1ba8ed717227810b81960 100644 --- a/Examples/Python/sim01_Particles/RotatedPyramids.py +++ b/Examples/Python/sim01_Particles/RotatedPyramids.py @@ -2,34 +2,44 @@ Rotated pyramids on top of substrate """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with rotated pyramids on top of a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - pyramid_ff = ba.FormFactorPyramid(10*nm, 5*nm, 54.73*deg) - pyramid = ba.Particle(m_particle, pyramid_ff) - transform = ba.RotationZ(45.*deg) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(pyramid, 1.0, ba.kvector_t(0.0, 0.0, 0.0), - transform) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorPyramid(10.0*nm, 5.0*nm, 54.73*deg) + + # Define particles + particle = ba.Particle(material_Particle, ff) + particle_rotation = ba.RotationZ(45.0*deg) + particle.setRotation(particle_rotation) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim01_Particles/TwoTypesOfCylindersWithSizeDistribution.py b/Examples/Python/sim01_Particles/TwoTypesOfCylindersWithSizeDistribution.py index 064dd0b650f93f2fb5723c3ac4cf960435ccbf9e..4609d50824a4e035e5a8a960b09a00ec1564754b 100644 --- a/Examples/Python/sim01_Particles/TwoTypesOfCylindersWithSizeDistribution.py +++ b/Examples/Python/sim01_Particles/TwoTypesOfCylindersWithSizeDistribution.py @@ -2,7 +2,7 @@ Mixture cylinder particles with different size distribution """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,57 +10,47 @@ def get_sample(): Returns a sample with cylinders in a homogeneous medium ("Vacuum"). The cylinders are a 95:5 mixture of two different size distributions. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - # collection of particles #1 - radius1 = 5.0*nm - height1 = radius1 - sigma1 = radius1*0.2 - - cylinder_ff1 = ba.FormFactorCylinder(radius1, height1) - cylinder1 = ba.Particle(m_particle, cylinder_ff1) - - gauss_distr1 = ba.DistributionGaussian(radius1, sigma1) - - nparticles = 150 - sigma_factor = 3.0 - - # limits will assure, that generated Radius'es are >=0 - limits = ba.RealLimits.nonnegative() - - par_distr1 = ba.ParameterDistribution("/Particle/Cylinder/Radius", - gauss_distr1, nparticles, - sigma_factor, limits) - part_coll1 = ba.ParticleDistribution(cylinder1, par_distr1) - - # collection of particles #2 - radius2 = 10.0*nm - height2 = radius2 - sigma2 = radius2*0.02 - - cylinder_ff2 = ba.FormFactorCylinder(radius2, height2) - cylinder2 = ba.Particle(m_particle, cylinder_ff2) - - gauss_distr2 = ba.DistributionGaussian(radius2, sigma2) - - par_distr2 = ba.ParameterDistribution("/Particle/Cylinder/Radius", - gauss_distr2, nparticles, - sigma_factor, limits) - part_coll2 = ba.ParticleDistribution(cylinder2, par_distr2) - - # assembling the sample - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(part_coll1, 0.95) - particle_layout.addParticle(part_coll2, 0.05) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - return multi_layer + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorCylinder(10.0*nm, 10.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + + # Define particles with parameter following a distribution + distr_1 = ba.DistributionGaussian(5.0*nm, 1.0*nm) + par_distr_1 = ba.ParameterDistribution("/Particle/Cylinder/Radius", + distr_1, 150, 3.0, + ba.RealLimits.nonnegative()) + particle_distrib_1 = ba.ParticleDistribution(particle_1, par_distr_1) + distr_2 = ba.DistributionGaussian(10.0*nm, 0.2*nm) + par_distr_2 = ba.ParameterDistribution("/Particle/Cylinder/Radius", + distr_2, 150, 3.0, + ba.RealLimits.nonnegative()) + particle_distrib_2 = ba.ParticleDistribution(particle_2, par_distr_2) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_distrib_1, 0.95) + layout.addParticle(particle_distrib_2, 0.05) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer = ba.Layer(material_Vacuum) + layer.addLayout(layout) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer) + + return sample def get_simulation(): diff --git a/Examples/Python/sim02_Complexes/BiMaterialCylinders.py b/Examples/Python/sim02_Complexes/BiMaterialCylinders.py index 959735afef08db72e1287c57a3e287d436c8ac55..d2c4b45a9bb0b4c96391021b1a34f63c5fec72c6 100644 --- a/Examples/Python/sim02_Complexes/BiMaterialCylinders.py +++ b/Examples/Python/sim02_Complexes/BiMaterialCylinders.py @@ -3,7 +3,7 @@ Cylindrical particle made from two materials. Particle crosses air/substrate interface. """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_composition(top_material, @@ -35,30 +35,47 @@ def get_sample(): Particle shifted down to cross interface. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 3.212e-6, 3.244e-8) - m_top_part = ba.HomogeneousMaterial("Ag", 1.245e-5, 5.419e-7) - m_bottom_part = ba.HomogeneousMaterial("Teflon", 2.900e-6, 6.019e-9) - - # collection of particles - composition = get_composition(m_top_part, m_bottom_part) - shift = 10.0*nm - composition.setPosition(0, 0, -shift) # will be shifted below interface - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(composition) - particle_layout.setTotalParticleSurfaceDensity(1) - - # vacuum layer with particles and substrate form multi layer - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - print(multi_layer.treeToString()) - return multi_layer + # Define materials + material_Ag = ba.HomogeneousMaterial("Ag", 1.245e-05, 5.419e-07) + material_Substrate = ba.HomogeneousMaterial("Substrate", 3.212e-06, + 3.244e-08) + material_Teflon = ba.HomogeneousMaterial("Teflon", 2.9e-06, 6.019e-09) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(10.0*nm, 4.0*nm) + ff_2 = ba.FormFactorCylinder(10.0*nm, 10.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Ag, ff_1) + particle_1_position = kvector_t(0.0*nm, 0.0*nm, 10.0*nm) + particle_1.setPosition(particle_1_position) + particle_2 = ba.Particle(material_Teflon, ff_2) + + # Define composition of particles at specific positions + particle_3 = ba.ParticleComposition() + particle_3.addParticle(particle_1) + particle_3.addParticle(particle_2) + particle_3_position = kvector_t(0.0*nm, 0.0*nm, -10.0*nm) + particle_3.setPosition(particle_3_position) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_3, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(1) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim02_Complexes/CoreShellNanoparticles.py b/Examples/Python/sim02_Complexes/CoreShellNanoparticles.py index 9f26bd7df5b29521b0bdc22b13511e63b0251200..0ff5326cf1f6ba7d591fdfa20063ec2540d3fde2 100644 --- a/Examples/Python/sim02_Complexes/CoreShellNanoparticles.py +++ b/Examples/Python/sim02_Complexes/CoreShellNanoparticles.py @@ -2,39 +2,49 @@ Core shell nanoparticles """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with box-shaped core-shell particles on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_shell = ba.HomogeneousMaterial("Shell", 1e-4, 2e-8) - m_core = ba.HomogeneousMaterial("Core", 6e-5, 2e-8) - - # collection of particles - parallelepiped1_ff = ba.FormFactorBox(16*nm, 16*nm, 8*nm) - parallelepiped2_ff = ba.FormFactorBox(12*nm, 12*nm, 7*nm) - shell_particle = ba.Particle(m_shell, parallelepiped1_ff) - core_particle = ba.Particle(m_core, parallelepiped2_ff) - core_position = ba.kvector_t(0.0, 0.0, 0.0) - - particle = ba.ParticleCoreShell(shell_particle, core_particle, - core_position) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(particle) - interference = ba.InterferenceFunctionNone() - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - - return multi_layer + + # Define materials + material_Core = ba.HomogeneousMaterial("Core", 6e-05, 2e-08) + material_Shell = ba.HomogeneousMaterial("Shell", 0.0001, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorBox(12.0*nm, 12.0*nm, 7.0*nm) + ff_2 = ba.FormFactorBox(16.0*nm, 16.0*nm, 8.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Core, ff_1) + particle_2 = ba.Particle(material_Shell, ff_2) + + # Define core shell particles + particle_3 = ba.ParticleCoreShell(particle_2, particle_1) + + # Define interference functions + iff = ba.InterferenceFunctionNone() + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_3, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer = ba.Layer(material_Vacuum) + layer.addLayout(layout) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer) + + return sample def get_simulation(): diff --git a/Examples/Python/sim02_Complexes/HexagonalLatticesWithBasis.py b/Examples/Python/sim02_Complexes/HexagonalLatticesWithBasis.py index 951758ed0b6e9422d2bcbbbd4002630943fdb26c..860732d97d96c21cdd8a05304edf2b4bc84b9855 100644 --- a/Examples/Python/sim02_Complexes/HexagonalLatticesWithBasis.py +++ b/Examples/Python/sim02_Complexes/HexagonalLatticesWithBasis.py @@ -3,7 +3,7 @@ Spheres on two hexagonal close packed layers """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -11,35 +11,53 @@ def get_sample(): Returns a sample with spheres on a substrate, forming two hexagonal close packed layers. """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - radius = 10.0*nm - sphere_ff = ba.FormFactorFullSphere(radius) - sphere = ba.Particle(m_particle, sphere_ff) - particle_layout = ba.ParticleLayout() - - pos0 = ba.kvector_t(0.0, 0.0, 0.0) - pos1 = ba.kvector_t(radius, radius, numpy.sqrt(3.0)*radius) - basis = ba.ParticleComposition() - basis.addParticles(sphere, [pos0, pos1]) - particle_layout.addParticle(basis) - - interference = ba.InterferenceFunction2DLattice( - ba.HexagonalLattice2D(radius*2.0, 0*deg)) - pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0) - interference.setDecayFunction(pdf) - - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate, 0) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorFullSphere(10.0*nm) + ff_2 = ba.FormFactorFullSphere(10.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + particle_2_position = kvector_t(10.0*nm, 10.0*nm, 17.3205080757*nm) + particle_2.setPosition(particle_2_position) + + # Define composition of particles at specific positions + particle_3 = ba.ParticleComposition() + particle_3.addParticle(particle_1) + particle_3.addParticle(particle_2) + + # Define 2D lattices + lattice = ba.BasicLattice2D(20.0*nm, 20.0*nm, 120.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(10.0*nm, 10.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_3, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.00288675134595) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim02_Complexes/MesoCrystal.py b/Examples/Python/sim02_Complexes/MesoCrystal.py index 84572be605e5ddaec54f1d863857048727e1c693..3bd203daadd04ab6d752e726b4b8dc616ddf2e31 100644 --- a/Examples/Python/sim02_Complexes/MesoCrystal.py +++ b/Examples/Python/sim02_Complexes/MesoCrystal.py @@ -2,46 +2,54 @@ Cylindrical mesocrystal on a substrate """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with a cylindrically shaped mesocrystal on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # mesocrystal lattice - lattice_basis_1 = ba.kvector_t(5.0, 0.0, 0.0) - lattice_basis_2 = ba.kvector_t(0.0, 5.0, 0.0) - lattice_basis_3 = ba.kvector_t(0.0, 0.0, 5.0) - lattice = ba.Lattice3D(lattice_basis_1, lattice_basis_2, lattice_basis_3) - - # spherical particle that forms the base of the mesocrystal - sphere_ff = ba.FormFactorFullSphere(2*nm) - sphere = ba.Particle(m_particle, sphere_ff) - - # crystal structure - crystal = ba.Crystal(sphere, lattice) - - # mesocrystal - meso_ff = ba.FormFactorCylinder(20*nm, 50*nm) - meso = ba.MesoCrystal(crystal, meso_ff) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(meso) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorFullSphere(2.0*nm) + ff_2 = ba.FormFactorCylinder(20.0*nm, 50.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + + # Define 3D lattices + lattice = ba.Lattice3D(ba.kvector_t(5.0*nm, 0.0*nm, 0.0*nm), + ba.kvector_t(0.0*nm, 5.0*nm, 0.0*nm), + ba.kvector_t(0.0*nm, 0.0*nm, 5.0*nm)) + + # Define crystals + crystal = ba.Crystal(particle_1, lattice) + + # Define mesocrystals + particle_2 = ba.MesoCrystal(crystal, ff_2) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_2, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim02_Complexes/ParticlesCrossingInterface.py b/Examples/Python/sim02_Complexes/ParticlesCrossingInterface.py index 870133138cfce84342c7e9af11db3d01847e0565..4065dbd16b0bebe16f00d52bd210fcf489f372e0 100644 --- a/Examples/Python/sim02_Complexes/ParticlesCrossingInterface.py +++ b/Examples/Python/sim02_Complexes/ParticlesCrossingInterface.py @@ -17,7 +17,7 @@ For example, X or Y rotated particles can not yet cross interfaces (exception will be thrown when trying to simulate such geometries). """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t phi_min, phi_max = -1.0, 1.0 alpha_min, alpha_max = 0.0, 2.0 @@ -27,37 +27,46 @@ def get_sample(): """ Returns a sample with uncorrelated cylinders and prisms on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - shift_down = 3*nm - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - cylinder.setPosition(0, 0, -shift_down) - - prism_ff = ba.FormFactorPrism3(10*nm, 5*nm) - prism = ba.Particle(m_particle, prism_ff) - prism.setPosition(0, 0, -shift_down) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 0.5) - particle_layout.addParticle(prism, 0.5) - interference = ba.InterferenceFunctionNone() - particle_layout.setInterferenceFunction(interference) - - # vacuum layer with particles and substrate form multi layer - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorPrism3(10.0*nm, 5.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_1_position = kvector_t(0.0*nm, 0.0*nm, -3.0*nm) + particle_1.setPosition(particle_1_position) + particle_2 = ba.Particle(material_Particle, ff_2) + particle_2_position = kvector_t(0.0*nm, 0.0*nm, -3.0*nm) + particle_2.setPosition(particle_2_position) + + # Define interference functions + iff = ba.InterferenceFunctionNone() + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_1, 0.5) + layout.addParticle(particle_2, 0.5) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/ApproximationDA.py b/Examples/Python/sim03_Structures/ApproximationDA.py index a6c5f9c4165b8f8845f4e3e704fa46e29e241051..c072968b804ba59f5effe416b447e620af14c038 100644 --- a/Examples/Python/sim03_Structures/ApproximationDA.py +++ b/Examples/Python/sim03_Structures/ApproximationDA.py @@ -2,7 +2,7 @@ Cylinders of two different sizes in Decoupling Approximation """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,40 +10,44 @@ def get_sample(): Returns a sample with cylinders of two different sizes on a substrate. The cylinder positions are modelled in Decoupling Approximation. """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # cylindrical particle 1 - radius1 = 5*nm - height1 = radius1 - cylinder_ff1 = ba.FormFactorCylinder(radius1, height1) - cylinder1 = ba.Particle(m_particle, cylinder_ff1) - - # cylindrical particle 2 - radius2 = 8*nm - height2 = radius2 - cylinder_ff2 = ba.FormFactorCylinder(radius2, height2) - cylinder2 = ba.Particle(m_particle, cylinder_ff2) - - # interference function - interference = ba.InterferenceFunctionRadialParaCrystal(18.0*nm, 1e3*nm) - pdf = ba.FTDistribution1DGauss(3*nm) - interference.setProbabilityDistribution(pdf) - - # assembling the sample - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder1, 0.8) - particle_layout.addParticle(cylinder2, 0.2) - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorCylinder(8.0*nm, 8.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + + # Define interference functions + iff = ba.InterferenceFunctionRadialParaCrystal(18.0*nm, 1000.0*nm) + iff_pdf = ba.FTDistribution1DGauss(3.0*nm) + iff.setProbabilityDistribution(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_1, 0.8) + layout.addParticle(particle_2, 0.2) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/ApproximationLMA.py b/Examples/Python/sim03_Structures/ApproximationLMA.py index 7417b465df286e2c58b310ad6e9070d550c933d9..73c8eebb9b3947f23b9da1de47a4608d8b17e872 100644 --- a/Examples/Python/sim03_Structures/ApproximationLMA.py +++ b/Examples/Python/sim03_Structures/ApproximationLMA.py @@ -2,7 +2,7 @@ Cylinders of two different sizes in Local Monodisperse Approximation """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,48 +10,52 @@ def get_sample(): Returns a sample with cylinders of two different sizes on a substrate. The cylinder positions are modelled in Local Monodisperse Approximation. """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # cylindrical particle 1 - radius1 = 5*nm - height1 = radius1 - cylinder_ff1 = ba.FormFactorCylinder(radius1, height1) - cylinder1 = ba.Particle(m_particle, cylinder_ff1) - - # cylindrical particle 2 - radius2 = 8*nm - height2 = radius2 - cylinder_ff2 = ba.FormFactorCylinder(radius2, height2) - cylinder2 = ba.Particle(m_particle, cylinder_ff2) - - # interference function1 - interference1 = ba.InterferenceFunctionRadialParaCrystal(16.8*nm, 1e3*nm) - pdf = ba.FTDistribution1DGauss(3*nm) - interference1.setProbabilityDistribution(pdf) - - # interference function2 - interference2 = ba.InterferenceFunctionRadialParaCrystal(22.8*nm, 1e3*nm) - interference2.setProbabilityDistribution(pdf) - - # assembling the sample - particle_layout1 = ba.ParticleLayout() - particle_layout1.addParticle(cylinder1, 0.8) - particle_layout1.setInterferenceFunction(interference1) - - particle_layout2 = ba.ParticleLayout() - particle_layout2.addParticle(cylinder2, 0.2) - particle_layout2.setInterferenceFunction(interference2) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout1) - vacuum_layer.addLayout(particle_layout2) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorCylinder(8.0*nm, 8.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + + # Define interference functions + iff_1 = ba.InterferenceFunctionRadialParaCrystal(16.8*nm, 1000.0*nm) + iff_1_pdf = ba.FTDistribution1DGauss(3.0*nm) + iff_1.setProbabilityDistribution(iff_1_pdf) + iff_2 = ba.InterferenceFunctionRadialParaCrystal(22.8*nm, 1000.0*nm) + iff_2_pdf = ba.FTDistribution1DGauss(3.0*nm) + iff_2.setProbabilityDistribution(iff_2_pdf) + + # Define particle layouts + layout_1 = ba.ParticleLayout() + layout_1.addParticle(particle_1, 0.8) + layout_1.setInterferenceFunction(iff_1) + layout_1.setWeight(1) + layout_1.setTotalParticleSurfaceDensity(0.01) + layout_2 = ba.ParticleLayout() + layout_2.addParticle(particle_2, 0.2) + layout_2.setInterferenceFunction(iff_2) + layout_2.setWeight(1) + layout_2.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout_1) + layer_1.addLayout(layout_2) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/ApproximationSSCA.py b/Examples/Python/sim03_Structures/ApproximationSSCA.py index 8948054bd8722e822fb8e82b6a0f0c6278b3ab2d..abc4a8cb83ba6dd9afedf41a54b0aa6ac54e53cf 100644 --- a/Examples/Python/sim03_Structures/ApproximationSSCA.py +++ b/Examples/Python/sim03_Structures/ApproximationSSCA.py @@ -2,7 +2,7 @@ Cylinders of two different sizes in Size-Spacing Coupling Approximation """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,41 +10,45 @@ def get_sample(): Returns a sample with cylinders of two different sizes on a substrate. The cylinder positions are modelled in Size-Spacing Coupling Approximation. """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # cylindrical particle 1 - radius1 = 5*nm - height1 = radius1 - cylinder_ff1 = ba.FormFactorCylinder(radius1, height1) - cylinder1 = ba.Particle(m_particle, cylinder_ff1) - - # cylindrical particle 2 - radius2 = 8*nm - height2 = radius2 - cylinder_ff2 = ba.FormFactorCylinder(radius2, height2) - cylinder2 = ba.Particle(m_particle, cylinder_ff2) - - # interference function - interference = ba.InterferenceFunctionRadialParaCrystal(18.0*nm, 1e3*nm) - pdf = ba.FTDistribution1DGauss(3*nm) - interference.setProbabilityDistribution(pdf) - interference.setKappa(1.0) - - # assembling the sample - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder1, 0.8) - particle_layout.addParticle(cylinder2, 0.2) - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorCylinder(8.0*nm, 8.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + + # Define interference functions + iff = ba.InterferenceFunctionRadialParaCrystal(18.0*nm, 1000.0*nm) + iff.setKappa(1.0) + iff_pdf = ba.FTDistribution1DGauss(3.0*nm) + iff.setProbabilityDistribution(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_1, 0.8) + layout.addParticle(particle_2, 0.2) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/CosineRipplesAtRectLattice.py b/Examples/Python/sim03_Structures/CosineRipplesAtRectLattice.py index 77a20d7b5340b2a4d8fcf94eb14006a52733f051..b4ae226890224b83dc62439efe2f945e434d0c20 100644 --- a/Examples/Python/sim03_Structures/CosineRipplesAtRectLattice.py +++ b/Examples/Python/sim03_Structures/CosineRipplesAtRectLattice.py @@ -3,7 +3,7 @@ Cosine ripple on a 2D lattice """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -11,33 +11,44 @@ def get_sample(): Returns a sample with cosine ripples on a substrate. The structure is modelled as a 2D Lattice. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - ff = ba.FormFactorCosineRippleBox(100*nm, 20*nm, 4*nm) - particle = ba.Particle(m_particle, ff) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(particle, 1.0) - - interference = ba.InterferenceFunction2DLattice( - ba.BasicLattice2D(200.0*nm, 50.0*nm, 90.0*deg, 0.0*deg)) - pdf = ba.FTDecayFunction2DCauchy(160*nm, 16*nm, 0) - interference.setDecayFunction(pdf) - particle_layout.setInterferenceFunction(interference) - - # assemble the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCosineRippleBox(100.0*nm, 20.0*nm, 4.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(200.0*nm, 50.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(160.0*nm, 16.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.0001) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference1DLattice.py b/Examples/Python/sim03_Structures/Interference1DLattice.py index 5e9301b2688fa4c52d7db33ac39ea489a82180c0..a23eb272e885653ac054d3856755eda4b986c84e 100644 --- a/Examples/Python/sim03_Structures/Interference1DLattice.py +++ b/Examples/Python/sim03_Structures/Interference1DLattice.py @@ -4,7 +4,7 @@ Monte-carlo integration is used to get rid of large-particle form factor oscillations. """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -12,36 +12,43 @@ def get_sample(): Returns a sample with a grating on a substrate, modelled by very long boxes forming a 1D lattice with Cauchy correlations. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - box_length, box_width, box_height = 10*nm, 10000*nm, 10*nm - lattice_length = 30*nm - - # collection of particles - interference = ba.InterferenceFunction1DLattice(lattice_length, 45*deg) - pdf = ba.FTDecayFunction1DCauchy(1000.0) - interference.setDecayFunction(pdf) - - box_ff = ba.FormFactorBox(box_length, box_width, box_height) - box = ba.Particle(m_particle, box_ff) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(box, 1.0, ba.kvector_t(0.0, 0.0, 0.0), - ba.RotationZ(45*deg)) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorBox(10.0*nm, 10000.0*nm, 10.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + particle_rotation = ba.RotationZ(45.0*deg) + particle.setRotation(particle_rotation) + + # Define interference functions + iff = ba.InterferenceFunction1DLattice(30.0*nm, 45.0*deg) + iff_pdf = ba.FTDecayFunction1DCauchy(1000.0*nm) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference1DRadialParaCrystal.py b/Examples/Python/sim03_Structures/Interference1DRadialParaCrystal.py index cadaf87bfafa237de006e92cf733744a2d712bbf..12e550a5a155149517eeca0327417769bcc95125 100644 --- a/Examples/Python/sim03_Structures/Interference1DRadialParaCrystal.py +++ b/Examples/Python/sim03_Structures/Interference1DRadialParaCrystal.py @@ -2,7 +2,7 @@ radial paracrystal """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t phi_min, phi_max = -2.0, 2.0 alpha_min, alpha_max = 0.0, 2.0 @@ -12,33 +12,41 @@ def get_sample(): """ Returns a sample with cylinders on a substrate that form a radial paracrystal. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - - interference = ba.InterferenceFunctionRadialParaCrystal(20.0*nm, 1e3*nm) - pdf = ba.FTDistribution1DGauss(7*nm) - interference.setProbabilityDistribution(pdf) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - # print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define interference functions + iff = ba.InterferenceFunctionRadialParaCrystal(20.0*nm, 1000.0*nm) + iff_pdf = ba.FTDistribution1DGauss(7.0*nm) + iff.setProbabilityDistribution(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference2DCenteredSquareLattice.py b/Examples/Python/sim03_Structures/Interference2DCenteredSquareLattice.py index cba7b06e579b352b77a7be10af0f6b5a8ecd0535..03049b3fb7b280223d910daf2450e1c90088194a 100644 --- a/Examples/Python/sim03_Structures/Interference2DCenteredSquareLattice.py +++ b/Examples/Python/sim03_Structures/Interference2DCenteredSquareLattice.py @@ -3,7 +3,7 @@ """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -11,38 +11,53 @@ def get_sample(): Returns a sample with cylinders on a substrate, forming a 2D centered square lattice """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - interference = ba.InterferenceFunction2DLattice( - ba.SquareLattice2D(25.0*nm, 0)) - pdf = ba.FTDecayFunction2DCauchy(48*nm, 16*nm, 0) - interference.setDecayFunction(pdf) - - particle_layout = ba.ParticleLayout() - position1 = ba.kvector_t(0.0, 0.0, 0.0) - position2 = ba.kvector_t(12.5*nm, 12.5*nm, 0.0) - cylinder_ff = ba.FormFactorCylinder(3.*nm, 3.*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - basis = ba.ParticleComposition() - basis.addParticles(cylinder, [position1, position2]) - particle_layout.addParticle(basis) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - - print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff_1 = ba.FormFactorCylinder(3.0*nm, 3.0*nm) + ff_2 = ba.FormFactorCylinder(3.0*nm, 3.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + particle_2_position = kvector_t(12.5*nm, 12.5*nm, 0.0*nm) + particle_2.setPosition(particle_2_position) + + # Define composition of particles at specific positions + particle_3 = ba.ParticleComposition() + particle_3.addParticle(particle_1) + particle_3.addParticle(particle_2) + + # Define 2D lattices + lattice = ba.BasicLattice2D(25.0*nm, 25.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(48.0*nm, 16.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle_3, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.0016) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference2DParaCrystal.py b/Examples/Python/sim03_Structures/Interference2DParaCrystal.py index 7a36395a45cc4f7ba2e4c46aebab24f9ee1c1ea8..dfae0d5c546f0ba8c4e51376d145db064bdf33d3 100644 --- a/Examples/Python/sim03_Structures/Interference2DParaCrystal.py +++ b/Examples/Python/sim03_Structures/Interference2DParaCrystal.py @@ -2,43 +2,54 @@ 2D paracrystal """ import bornagain as ba -from bornagain import deg, angstrom, nm, micrometer +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with cylinders on a substrate, forming a 2D paracrystal """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(4*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - - interference = ba.InterferenceFunction2DParaCrystal( - ba.SquareLattice2D(10.0*nm), 0.0, 20.0*micrometer, 20.0*micrometer) - interference.setIntegrationOverXi(True) - pdf = ba.FTDistribution2DCauchy(1.0*nm, 1.0*nm, 0) - interference.setProbabilityDistributions(pdf, pdf) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - print(multi_layer.parametersToString()) - print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(4.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(10.0*nm, 10.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DParaCrystal(lattice, 0.0*nm, 20000.0*nm, + 20000.0*nm) + iff.setIntegrationOverXi(True) + iff_pdf_1 = ba.FTDistribution2DCauchy(1.0*nm, 1.0*nm, 0.0*deg) + iff_pdf_2 = ba.FTDistribution2DCauchy(1.0*nm, 1.0*nm, 0.0*deg) + iff.setProbabilityDistributions(iff_pdf_1, iff_pdf_2) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference2DRotatedSquareLattice.py b/Examples/Python/sim03_Structures/Interference2DRotatedSquareLattice.py index 77e4bac2e6cbeef19984ad02b5c4a6051c33f242..33ec3f79809db7ed9ef3666054966b6723863b70 100644 --- a/Examples/Python/sim03_Structures/Interference2DRotatedSquareLattice.py +++ b/Examples/Python/sim03_Structures/Interference2DRotatedSquareLattice.py @@ -3,41 +3,52 @@ Cylinders on a rotated 2D lattice """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with cylinders on a substrate, forming a rotated 2D lattice """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - interference = ba.InterferenceFunction2DLattice( - ba.SquareLattice2D(25.0*nm, 30.0*deg)) - pdf = ba.FTDecayFunction2DCauchy(300.0*nm/2.0/numpy.pi, - 100.0*nm/2.0/numpy.pi, 0) - pdf.setParameterValue("Gamma", 30.0*deg) - interference.setDecayFunction(pdf) - - cylinder_ff = ba.FormFactorCylinder(3.*nm, 3.*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - - substrate_layer = ba.Layer(m_substrate) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(3.0*nm, 3.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(25.0*nm, 25.0*nm, 90.0*deg, 30.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(47.7464829276*nm, 15.9154943092*nm, + 30.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.0016) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference2DSquareFiniteLattice.py b/Examples/Python/sim03_Structures/Interference2DSquareFiniteLattice.py index 937cfc666c07e551253fb739d74c42fd86328950..e018b063c317bb9935640c8dce3f10b1fd4ffff5 100644 --- a/Examples/Python/sim03_Structures/Interference2DSquareFiniteLattice.py +++ b/Examples/Python/sim03_Structures/Interference2DSquareFiniteLattice.py @@ -3,40 +3,50 @@ Cylinders on a 2D square lattice """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with cylinders on a substrate, forming a 2D square lattice. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - interference = ba.InterferenceFunctionFinite2DLattice( - ba.SquareLattice2D(25.0*nm, 0.0), 40, 40) - interference.setPositionVariance(1.0) - - cylinder_ff = ba.FormFactorCylinder(3.*nm, 3.*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - print(multi_layer.parametersToString()) - print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(3.0*nm, 3.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(25.0*nm, 25.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunctionFinite2DLattice(lattice, 40, 40) + iff.setPositionVariance(1.0*nm2) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.0016) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/Interference2DSquareLattice.py b/Examples/Python/sim03_Structures/Interference2DSquareLattice.py index 37d7668d657953e2367eb552d6ee82f9ecd24e99..affd7715ec59e66c594c4acf5a22332d0da8d990 100644 --- a/Examples/Python/sim03_Structures/Interference2DSquareLattice.py +++ b/Examples/Python/sim03_Structures/Interference2DSquareLattice.py @@ -3,41 +3,51 @@ Cylinders on a 2D square lattice """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with cylinders on a substrate, forming a 2D square lattice. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - interference = ba.InterferenceFunction2DLattice( - ba.SquareLattice2D(25.0*nm, 0*deg)) - pdf = ba.FTDecayFunction2DCauchy(48*nm, 16*nm, 0) - interference.setDecayFunction(pdf) - - cylinder_ff = ba.FormFactorCylinder(3.*nm, 3.*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - print(multi_layer.parametersToString()) - print(multi_layer.treeToString()) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(3.0*nm, 3.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(25.0*nm, 25.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(48.0*nm, 16.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.0016) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/SpheresAtHexLattice.py b/Examples/Python/sim03_Structures/SpheresAtHexLattice.py index 61dfea83cdebb8a497f50c002c03fe99b933dcc1..7f3c49d042b4f7e05fa5b942c17900b3816cb40e 100644 --- a/Examples/Python/sim03_Structures/SpheresAtHexLattice.py +++ b/Examples/Python/sim03_Structures/SpheresAtHexLattice.py @@ -2,7 +2,7 @@ Spheres on a hexagonal lattice """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,29 +10,44 @@ def get_sample(): Returns a sample with spherical particles on a substrate, forming a hexagonal 2D lattice. """ - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - sphere_ff = ba.FormFactorFullSphere(10.0*nm) - sphere = ba.Particle(m_particle, sphere_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(sphere) - - interference = ba.InterferenceFunction2DLattice( - ba.HexagonalLattice2D(20.0*nm, 0*deg)) - pdf = ba.FTDecayFunction2DCauchy(10*nm, 10*nm, 0) - interference.setDecayFunction(pdf) - - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate, 0) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorFullSphere(10.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(20.0*nm, 20.0*nm, 120.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(10.0*nm, 10.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.00288675134595) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim03_Structures/TriangularRipple.py b/Examples/Python/sim03_Structures/TriangularRipple.py index 88f23668861e2d03f21c2b989338b40c6740c8aa..2815287042a10a22f4e7cb04849b1132650fd8b9 100644 --- a/Examples/Python/sim03_Structures/TriangularRipple.py +++ b/Examples/Python/sim03_Structures/TriangularRipple.py @@ -3,7 +3,7 @@ """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -11,34 +11,45 @@ def get_sample(): Returns a sample with a grating on a substrate, modelled by triangular ripples forming a 1D Paracrystal. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - ripple2_ff = ba.FormFactorSawtoothRippleBox(100*nm, 20*nm, 4*nm, -3.0*nm) - ripple = ba.Particle(m_particle, ripple2_ff) - - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(ripple, 1.0) - - interference = ba.InterferenceFunction2DLattice( - ba.BasicLattice2D(200.0*nm, 50.0*nm, 90.0*deg, 0.0*deg)) - pdf = ba.FTDecayFunction2DGauss(1000.*nm/2./numpy.pi, 100.*nm/2./numpy.pi, - 0) - interference.setDecayFunction(pdf) - particle_layout.setInterferenceFunction(interference) - - # vacuum layer with particles and substrate form multi layer - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate, 0) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorSawtoothRippleBox(100.0*nm, 20.0*nm, 4.0*nm, -3.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(200.0*nm, 50.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DGauss(159.154943092*nm, 15.9154943092*nm, + 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.0001) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim04_Multilayers/BuriedParticles.py b/Examples/Python/sim04_Multilayers/BuriedParticles.py index 64a9e3c72b5d035020ee3f7985a579930cc16073..d543571da20b84d28b480c3c3dcc2cec353c3d3c 100644 --- a/Examples/Python/sim04_Multilayers/BuriedParticles.py +++ b/Examples/Python/sim04_Multilayers/BuriedParticles.py @@ -2,7 +2,7 @@ Spherical particles embedded in the middle of the layer on top of substrate. """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -10,30 +10,41 @@ def get_sample(): Returns a sample with spherical particles in a layer between vacuum and substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_interm_layer = ba.HomogeneousMaterial("IntermLayer", 3.45e-6, 5.24e-9) - m_substrate = ba.HomogeneousMaterial("Substrate", 7.43e-6, 1.72e-7) - m_particle = ba.HomogeneousMaterial("Particle", 0.0, 0.0) - # collection of particles + # Define materials + material_IntermLayer = ba.HomogeneousMaterial("IntermLayer", 3.45e-06, + 5.24e-09) + material_Particle = ba.HomogeneousMaterial("Particle", 0.0, 0.0) + material_Substrate = ba.HomogeneousMaterial("Substrate", 7.43e-06, 1.72e-07) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors ff = ba.FormFactorFullSphere(10.2*nm) - sphere = ba.Particle(m_particle, ff) - sphere.setPosition(0.0, 0.0, -25.2) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(sphere, 1.0) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - intermediate_layer = ba.Layer(m_interm_layer, 30.*nm) - intermediate_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate, 0) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(intermediate_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define particles + particle = ba.Particle(material_Particle, ff) + particle_position = kvector_t(0.0*nm, 0.0*nm, -25.2*nm) + particle.setPosition(particle_position) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_2 = ba.Layer(material_IntermLayer, 30.0*nm) + layer_2.addLayout(layout) + layer_3 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + sample.addLayer(layer_3) + + return sample def get_simulation(): diff --git a/Examples/Python/sim04_Multilayers/HalfSpheresInAverageTopLayer.py b/Examples/Python/sim04_Multilayers/HalfSpheresInAverageTopLayer.py index ff0079a2ef201aced9c1c09b05021c1fd984a61b..a691fbab52d14a78ea9c97b1a90129aade4781e1 100644 --- a/Examples/Python/sim04_Multilayers/HalfSpheresInAverageTopLayer.py +++ b/Examples/Python/sim04_Multilayers/HalfSpheresInAverageTopLayer.py @@ -3,7 +3,7 @@ Square lattice of half spheres on substrate with usage of average material and slicing """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t sphere_radius = 5*nm n_slices = 10 @@ -13,35 +13,45 @@ def get_sample(): """ Returns a sample with cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_layer = ba.HomogeneousMaterial("Layer", 3e-6, 2e-8) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 3e-5, 2e-8) - - # cylindrical particle - half_sphere_ff = ba.FormFactorTruncatedSphere(sphere_radius, sphere_radius, - 0) - half_sphere = ba.Particle(m_particle, half_sphere_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(half_sphere) - - # interference function - interference = ba.InterferenceFunction2DLattice( - ba.SquareLattice2D(10*nm, 0*deg)) - pdf = ba.FTDecayFunction2DCauchy(100*nm, 100*nm, 0) - interference.setDecayFunction(pdf) - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - vacuum_layer.setNumberOfSlices(n_slices) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 3e-05, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorTruncatedSphere(5.0*nm, 5.0*nm, 0.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(10.0*nm, 10.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(100.0*nm, 100.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.setNumberOfSlices(10) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim05_Magnetism/MagneticSpheres.py b/Examples/Python/sim05_Magnetism/MagneticSpheres.py index e6173541e6032358a1b351c0795b51eb5a3e8f19..1b6277ea0a801dfb4a98908c95612aabf6fd4a44 100644 --- a/Examples/Python/sim05_Magnetism/MagneticSpheres.py +++ b/Examples/Python/sim05_Magnetism/MagneticSpheres.py @@ -2,7 +2,7 @@ Simulation demo: magnetic spheres in substrate """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t # Magnetization of the particle's material (A/m) magnetization_particle = ba.kvector_t(0.0, 0.0, 1e7) @@ -12,30 +12,39 @@ def get_sample(): """ Returns a sample with magnetic spheres in the substrate. """ - # defining materials - particle_material = ba.HomogeneousMaterial("Particle", 2e-5, 4e-7, - magnetization_particle) - vacuum_material = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - substrate_material = ba.HomogeneousMaterial("Substrate", 7e-6, 1.8e-7) - - # spherical magnetic particle - sphere_ff = ba.FormFactorFullSphere(5*nm) - sphere = ba.Particle(particle_material, sphere_ff) - position = ba.kvector_t(0.0, 0.0, -10.0*nm) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(sphere, 1.0, position) - - # defining layers - vacuum_layer = ba.Layer(vacuum_material) - substrate_layer = ba.Layer(substrate_material) - substrate_layer.addLayout(particle_layout) - - # defining the multilayer - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - - return multi_layer + + # Define materials + magnetic_field = kvector_t(0, 0, 10000000) + material_Particle = ba.HomogeneousMaterial("Particle", 2e-05, 4e-07, + magnetic_field) + material_Substrate = ba.HomogeneousMaterial("Substrate", 7e-06, 1.8e-07) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorFullSphere(5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + particle_position = kvector_t(0.0*nm, 0.0*nm, -10.0*nm) + particle.setPosition(particle_position) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_2 = ba.Layer(material_Substrate) + layer_2.addLayout(layout) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim11_Device/AxesInDifferentUnits.py b/Examples/Python/sim11_Device/AxesInDifferentUnits.py index 684c7f176215f04d59aff02ab950e64cf5b81702..95eb46e47e4608d0c88c4b765ea8a801be03adf9 100644 --- a/Examples/Python/sim11_Device/AxesInDifferentUnits.py +++ b/Examples/Python/sim11_Device/AxesInDifferentUnits.py @@ -3,7 +3,7 @@ In this example we demonstrate how to plot simulation results with axes in different units (nbins, mm, degs and QyQz). """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t from matplotlib import pyplot as plt from matplotlib import rcParams @@ -12,25 +12,35 @@ def get_sample(): """ Returns a sample with uncorrelated cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_rectangular_detector(): diff --git a/Examples/Python/sim11_Device/BeamDivergence.py b/Examples/Python/sim11_Device/BeamDivergence.py index d3bd4386de5798ffe65fcbdf202d102f2a2dfe07..9fdc00c06f875932142dd7e433719193725f30e0 100644 --- a/Examples/Python/sim11_Device/BeamDivergence.py +++ b/Examples/Python/sim11_Device/BeamDivergence.py @@ -2,33 +2,42 @@ Cylinder form factor in DWBA with beam divergence """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with uncorrelated cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim11_Device/ConstantBackground.py b/Examples/Python/sim11_Device/ConstantBackground.py index 72d4236ca93d96cdd9e7138ecb612f205e33e4f5..75935b4b9c9b04a5bcd5f0a08c49f783e4219943 100644 --- a/Examples/Python/sim11_Device/ConstantBackground.py +++ b/Examples/Python/sim11_Device/ConstantBackground.py @@ -2,33 +2,42 @@ Cylinder form factor in DWBA with constant background """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with uncorrelated cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim11_Device/DetectorResolutionFunction.py b/Examples/Python/sim11_Device/DetectorResolutionFunction.py index 9b06b4de856731fee54104a25ca276f8768e5e9e..5add835f7998d4aad0f4c544aee6734061adfb37 100644 --- a/Examples/Python/sim11_Device/DetectorResolutionFunction.py +++ b/Examples/Python/sim11_Device/DetectorResolutionFunction.py @@ -2,33 +2,42 @@ Cylinder form factor in DWBA with detector resolution function applied """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with uncorrelated cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim11_Device/OffSpecularSimulation.py b/Examples/Python/sim11_Device/OffSpecularSimulation.py index 825ece1c4ca575ffbf2de05ffd8cabea2af1d538..fae853ac2cf200101b68f245ea4b10bfbfcc603c 100644 --- a/Examples/Python/sim11_Device/OffSpecularSimulation.py +++ b/Examples/Python/sim11_Device/OffSpecularSimulation.py @@ -2,7 +2,7 @@ Long boxes at 1D lattice, ba.OffSpecular simulation """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t phi_f_min, phi_f_max = -1.0, 1.0 alpha_f_min, alpha_f_max = 0.0, 10.0 @@ -14,36 +14,43 @@ def get_sample(): Returns a sample with a grating on a substrate, modelled by infinitely long boxes forming a 1D lattice. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - lattice_length = 100.0*nm - lattice_rotation_angle = 0.0*deg - interference = ba.InterferenceFunction1DLattice(lattice_length, - lattice_rotation_angle) - pdf = ba.FTDecayFunction1DCauchy(1e+6) - interference.setDecayFunction(pdf) - - box_ff = ba.FormFactorBox(1000*nm, 20*nm, 10.0*nm) - box = ba.Particle(m_particle, box_ff) - transform = ba.RotationZ(90.0*deg) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(box, 1.0, ba.kvector_t(0.0, 0.0, 0.0), - transform) - particle_layout.setInterferenceFunction(interference) - - # assembling the sample - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorBox(1000.0*nm, 20.0*nm, 10.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + particle_rotation = ba.RotationZ(90.0*deg) + particle.setRotation(particle_rotation) + + # Define interference functions + iff = ba.InterferenceFunction1DLattice(100.0*nm, 0.0*deg) + iff_pdf = ba.FTDecayFunction1DCauchy(1000000.0*nm) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim11_Device/RectangularDetector.py b/Examples/Python/sim11_Device/RectangularDetector.py index 97891089d3c6b71d1a8d45ea06188c56ed6cdfd4..cabd270157fa3e12a2b23ae0b7e9920dbe2968df 100644 --- a/Examples/Python/sim11_Device/RectangularDetector.py +++ b/Examples/Python/sim11_Device/RectangularDetector.py @@ -4,7 +4,7 @@ Results will be compared against simulation with spherical detector. """ import numpy import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t import matplotlib from matplotlib import pyplot as plt @@ -17,26 +17,35 @@ def get_sample(): """ Returns a sample with cylindrical particles on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - edge = 40*nm - ff = ba.FormFactorBox(edge, edge, edge) - cylinder = ba.Particle(m_particle, ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorBox(40.0*nm, 40.0*nm, 40.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_spherical_detector(): diff --git a/Examples/Python/sim21_Reflectometry/BasicPolarizedReflectometry.py b/Examples/Python/sim21_Reflectometry/BasicPolarizedReflectometry.py index 646c07d16f9ca6b611d2a36012146b15fa86504a..a61b8f9da614369882137b1e201b4eba94cbb7da 100644 --- a/Examples/Python/sim21_Reflectometry/BasicPolarizedReflectometry.py +++ b/Examples/Python/sim21_Reflectometry/BasicPolarizedReflectometry.py @@ -4,7 +4,7 @@ magnetized sample. """ import bornagain as ba -from bornagain import deg, angstrom +from bornagain import angstrom, deg, nm, nm2, kvector_t import matplotlib.pyplot as plt @@ -14,24 +14,24 @@ def get_sample(): Defines sample and returns it """ - # creating materials - m_ambient = ba.MaterialBySLD("Ambient", 0.0, 0.0) - m_layer_mat = ba.MaterialBySLD("Layer", 1e-4, 1e-8, - ba.kvector_t(0.0, 1e8, 0.0)) - m_substrate = ba.MaterialBySLD("Substrate", 7e-5, 2e-6) + # Define materials + material_Ambient = ba.MaterialBySLD("Ambient", 0.0, 0.0) + magnetic_field = kvector_t(0, 100000000, 0) + material_Layer = ba.MaterialBySLD("Layer", 0.0001, 1e-08, magnetic_field) + material_Substrate = ba.MaterialBySLD("Substrate", 7e-05, 2e-06) - # creating layers - ambient_layer = ba.Layer(m_ambient) - layer = ba.Layer(m_layer_mat, 10) - substrate_layer = ba.Layer(m_substrate) + # Define layers + layer_1 = ba.Layer(material_Ambient) + layer_2 = ba.Layer(material_Layer, 10.0*nm) + layer_3 = ba.Layer(material_Substrate) - # creating multilayer - multi_layer = ba.MultiLayer() - multi_layer.addLayer(ambient_layer) - multi_layer.addLayer(layer) - multi_layer.addLayer(substrate_layer) + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + sample.addLayer(layer_3) - return multi_layer + return sample def get_simulation(scan_size=500): diff --git a/Examples/Python/sim21_Reflectometry/PolarizedNoAnalyzer.py b/Examples/Python/sim21_Reflectometry/PolarizedNoAnalyzer.py index 789e705a95ae5cecfaff682bbde8583ecb86b9fe..3be7294ae9257c39797f09005a7d29121cd65613 100644 --- a/Examples/Python/sim21_Reflectometry/PolarizedNoAnalyzer.py +++ b/Examples/Python/sim21_Reflectometry/PolarizedNoAnalyzer.py @@ -6,7 +6,7 @@ import numpy import matplotlib.pyplot as plt import bornagain as ba -from bornagain import deg, angstrom +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -14,29 +14,24 @@ def get_sample(): Defines sample and returns it """ - # creating materials - magnetizationMagnitude = 1e8 - angle = 30*deg - magnetizationVector = ba.kvector_t(magnetizationMagnitude*numpy.sin(angle), - magnetizationMagnitude*numpy.cos(angle), - 0) - - m_ambient = ba.MaterialBySLD("Ambient", 0.0, 0.0) - m_layer_mat = ba.MaterialBySLD("Layer", 1e-4, 1e-8, magnetizationVector) - m_substrate = ba.MaterialBySLD("Substrate", 7e-5, 2e-6) - - # creating layers - ambient_layer = ba.Layer(m_ambient) - layer = ba.Layer(m_layer_mat, 10) - substrate_layer = ba.Layer(m_substrate) - - # creating multilayer - multi_layer = ba.MultiLayer() - multi_layer.addLayer(ambient_layer) - multi_layer.addLayer(layer) - multi_layer.addLayer(substrate_layer) - - return multi_layer + # Define materials + material_Ambient = ba.MaterialBySLD("Ambient", 0.0, 0.0) + magnetic_field = kvector_t(50000000, 86602540.3784, 0) + material_Layer = ba.MaterialBySLD("Layer", 0.0001, 1e-08, magnetic_field) + material_Substrate = ba.MaterialBySLD("Substrate", 7e-05, 2e-06) + + # Define layers + layer_1 = ba.Layer(material_Ambient) + layer_2 = ba.Layer(material_Layer, 10.0*nm) + layer_3 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + sample.addLayer(layer_3) + + return sample def get_simulation(scan_size=500): diff --git a/Examples/Python/sim21_Reflectometry/PolarizedSpinFlip.py b/Examples/Python/sim21_Reflectometry/PolarizedSpinFlip.py index ae84979c89406edf2d92a4c0037fc6742170281a..901087ebb03e3a7cdba54d300c2bdb7811e9a2e2 100644 --- a/Examples/Python/sim21_Reflectometry/PolarizedSpinFlip.py +++ b/Examples/Python/sim21_Reflectometry/PolarizedSpinFlip.py @@ -5,7 +5,7 @@ a magnetized sample. import numpy import bornagain as ba -from bornagain import deg, angstrom +from bornagain import angstrom, deg, nm, nm2, kvector_t import matplotlib.pyplot as plt @@ -15,30 +15,24 @@ def get_sample(): Defines sample and returns it """ - # parametrize the magnetization - magnetizationMagnitude = 1e8 - angle = 30*deg - magnetizationVector = ba.kvector_t(magnetizationMagnitude*numpy.sin(angle), - magnetizationMagnitude*numpy.cos(angle), - 0) - - # creating materials - m_ambient = ba.MaterialBySLD("Ambient", 0.0, 0.0) - m_layer_mat = ba.MaterialBySLD("Layer", 1e-4, 1e-8, magnetizationVector) - m_substrate = ba.MaterialBySLD("Substrate", 7e-5, 2e-6) - - # creating layers - ambient_layer = ba.Layer(m_ambient) - layer = ba.Layer(m_layer_mat, 10) - substrate_layer = ba.Layer(m_substrate) - - # creating multilayer - multi_layer = ba.MultiLayer() - multi_layer.addLayer(ambient_layer) - multi_layer.addLayer(layer) - multi_layer.addLayer(substrate_layer) - - return multi_layer + # Define materials + material_Ambient = ba.MaterialBySLD("Ambient", 0.0, 0.0) + magnetic_field = kvector_t(50000000, 86602540.3784, 0) + material_Layer = ba.MaterialBySLD("Layer", 0.0001, 1e-08, magnetic_field) + material_Substrate = ba.MaterialBySLD("Substrate", 7e-05, 2e-06) + + # Define layers + layer_1 = ba.Layer(material_Ambient) + layer_2 = ba.Layer(material_Layer, 10.0*nm) + layer_3 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + sample.addLayer(layer_3) + + return sample def get_simulation(scan_size=500): diff --git a/Examples/Python/sim22_OffSpecular/BoxesWithSpecularPeak.py b/Examples/Python/sim22_OffSpecular/BoxesWithSpecularPeak.py index 7a770a1f547bc6f665419b75a89293aa7f74d377..e5d58ff02734e888aacc75f51f14792d2d29278d 100644 --- a/Examples/Python/sim22_OffSpecular/BoxesWithSpecularPeak.py +++ b/Examples/Python/sim22_OffSpecular/BoxesWithSpecularPeak.py @@ -2,39 +2,51 @@ Square lattice of boxes on substrate (including the specular peak) """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): """ Returns a sample with boxes on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 3e-5, 2e-8) - - # cylindrical particle - box_ff = ba.FormFactorBox(5*nm, 5*nm, 10*nm) - box = ba.Particle(m_particle, box_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(box) - - # interference function - interference = ba.InterferenceFunction2DLattice( - ba.SquareLattice2D(8*nm, 0*deg)) - pdf = ba.FTDecayFunction2DCauchy(100*nm, 100*nm, 0) - interference.setDecayFunction(pdf) - particle_layout.setInterferenceFunction(interference) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 3e-05, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorBox(5.0*nm, 5.0*nm, 10.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define 2D lattices + lattice = ba.BasicLattice2D(8.0*nm, 8.0*nm, 90.0*deg, 0.0*deg) + + # Define interference functions + iff = ba.InterferenceFunction2DLattice(lattice) + iff_pdf = ba.FTDecayFunction2DCauchy(100.0*nm, 100.0*nm, 0.0*deg) + iff.setDecayFunction(iff_pdf) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.015625) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim23_SAS/PolarizedSANS.py b/Examples/Python/sim23_SAS/PolarizedSANS.py index 3728621a111b0faae8ea7e01f1dce245b905daeb..eff2352864e67fb3f72c99bb0de61adebcfe60f9 100644 --- a/Examples/Python/sim23_SAS/PolarizedSANS.py +++ b/Examples/Python/sim23_SAS/PolarizedSANS.py @@ -4,7 +4,7 @@ simulated with BornAgain. """ import bornagain as ba -from bornagain import deg, nm, kvector_t +from bornagain import angstrom, deg, nm, nm2, kvector_t # Magnetization of the particle's core material (A/m) magnetization_core = kvector_t(0.0, 0.0, 1e7) @@ -14,31 +14,41 @@ def get_sample(): """ Returns a sample with a magnetic core-shell particle in a solvent. """ - # Defining Materials - mat_solvent = ba.HomogeneousMaterial("Solvent", 5e-6, 0.0) - mat_core = ba.HomogeneousMaterial("Core", 6e-6, 2e-8, magnetization_core) - mat_shell = ba.HomogeneousMaterial("Shell", 1e-7, 2e-8) - # Defining Layer - solvent_layer = ba.Layer(mat_solvent) + # Define materials + magnetic_field = kvector_t(0, 0, 10000000) + material_Core = ba.HomogeneousMaterial("Core", 6e-06, 2e-08, magnetic_field) + material_Shell = ba.HomogeneousMaterial("Shell", 1e-07, 2e-08) + material_Solvent = ba.HomogeneousMaterial("Solvent", 5e-06, 0.0) - # Defining particle layout with a core-shell particle + # Define form factors + ff_1 = ba.FormFactorFullSphere(10.0*nm) + ff_2 = ba.FormFactorFullSphere(12.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Core, ff_1) + particle_1_position = kvector_t(0.0*nm, 0.0*nm, 2.0*nm) + particle_1.setPosition(particle_1_position) + particle_2 = ba.Particle(material_Shell, ff_2) + + # Define core shell particles + particle_3 = ba.ParticleCoreShell(particle_2, particle_1) + + # Define particle layouts layout = ba.ParticleLayout() - core_sphere_ff = ba.FormFactorFullSphere(10*nm) - shell_sphere_ff = ba.FormFactorFullSphere(12*nm) - core = ba.Particle(mat_core, core_sphere_ff) - shell = ba.Particle(mat_shell, shell_sphere_ff) - position = kvector_t(0.0, 0.0, 2.0) - particleCoreShell = ba.ParticleCoreShell(shell, core, position) - layout.addParticle(particleCoreShell) - - # Adding layout to layer - solvent_layer.addLayout(layout) - - # Defining Multilayer with single layer - multiLayer = ba.MultiLayer() - multiLayer.addLayer(solvent_layer) - return multiLayer + layout.addParticle(particle_3, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer = ba.Layer(material_Solvent) + layer.addLayout(layout) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer) + + return sample def get_simulation(): diff --git a/Examples/Python/sim29_DepthProbe/DepthProbe.py b/Examples/Python/sim29_DepthProbe/DepthProbe.py index a27ef8e6b33217183d5f58949172ec9483553ba8..22de45ab8dae4c9be84d3f70d54bbcf8cb0b22af 100644 --- a/Examples/Python/sim29_DepthProbe/DepthProbe.py +++ b/Examples/Python/sim29_DepthProbe/DepthProbe.py @@ -24,7 +24,7 @@ to the sample, z = 0 corresponding to the sample surface """ import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t # layer thicknesses in angstroms t_Ti = 130.0*angstrom @@ -55,31 +55,29 @@ def get_sample(): Constructs a sample with one resonating Ti/Pt layer """ - # define materials - m_Si = ba.HomogeneousMaterial("Si", 3.3009e-05, 0.0) - m_Ti = ba.HomogeneousMaterial("Ti", -3.0637e-05, 1.5278e-08) - m_TiO2 = ba.HomogeneousMaterial("TiO2", 4.1921e-05, 8.1293e-09) - m_Pt = ba.HomogeneousMaterial("Pt", 1.0117e-04, 3.01822e-08) - m_D2O = ba.HomogeneousMaterial("D2O", 1.0116e-04, 1.8090e-12) - - # create layers - l_Si = ba.Layer(m_Si) - l_Ti = ba.Layer(m_Ti, 130.0*angstrom) - l_Pt = ba.Layer(m_Pt, 320.0*angstrom) - l_Ti_top = ba.Layer(m_Ti, 100.0*angstrom) - l_TiO2 = ba.Layer(m_TiO2, 30.0*angstrom) - l_D2O = ba.Layer(m_D2O) - - # construct sample + # Define materials + material_D2O = ba.HomogeneousMaterial("D2O", 0.00010116, 1.809e-12) + material_Pt = ba.HomogeneousMaterial("Pt", 0.00010117, 3.01822e-08) + material_Si = ba.HomogeneousMaterial("Si", 3.3009e-05, 0.0) + material_Ti = ba.HomogeneousMaterial("Ti", -3.0637e-05, 1.5278e-08) + material_TiO2 = ba.HomogeneousMaterial("TiO2", 4.1921e-05, 8.1293e-09) + + # Define layers + layer_1 = ba.Layer(material_Si) + layer_2 = ba.Layer(material_Ti, 13.0*nm) + layer_3 = ba.Layer(material_Pt, 32.0*nm) + layer_4 = ba.Layer(material_Ti, 10.0*nm) + layer_5 = ba.Layer(material_TiO2, 3.0*nm) + layer_6 = ba.Layer(material_D2O) + + # Define sample sample = ba.MultiLayer() - sample.addLayer(l_Si) - - sample.addLayer(l_Ti) - sample.addLayer(l_Pt) - - sample.addLayer(l_Ti_top) - sample.addLayer(l_TiO2) - sample.addLayer(l_D2O) + sample.addLayer(layer_1) + sample.addLayer(layer_2) + sample.addLayer(layer_3) + sample.addLayer(layer_4) + sample.addLayer(layer_5) + sample.addLayer(layer_6) return sample diff --git a/Examples/Python/sim31_Parameterization/AccessingSimulationResults.py b/Examples/Python/sim31_Parameterization/AccessingSimulationResults.py index a443761cff9f7168a8f16093be9c2cf5ff957eb5..5dd69b16e2eebbd937a9ad7d7c6944ce0eb5346e 100644 --- a/Examples/Python/sim31_Parameterization/AccessingSimulationResults.py +++ b/Examples/Python/sim31_Parameterization/AccessingSimulationResults.py @@ -5,7 +5,7 @@ The standard "Cylinders in DWBA" sample is used to setup the simulation. import math import random import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t from matplotlib import pyplot as plt from matplotlib import rcParams @@ -14,25 +14,35 @@ def get_sample(): """ Returns a sample with uncorrelated cylinders on a substrate. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - particle_layout = ba.ParticleLayout() - particle_layout.addParticle(cylinder, 1.0) - - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(particle_layout) - substrate_layer = ba.Layer(m_substrate) - - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + + # Define form factors + ff = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + + # Define particles + particle = ba.Particle(material_Particle, ff) + + # Define particle layouts + layout = ba.ParticleLayout() + layout.addParticle(particle, 1.0) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/Python/sim31_Parameterization/SimulationParameters.py b/Examples/Python/sim31_Parameterization/SimulationParameters.py index 39481ad8338e6fdf91bc41dee35cebbc5c9088cf..195210a3e01c8bc8fc9c285a56b841766fbd7b7e 100644 --- a/Examples/Python/sim31_Parameterization/SimulationParameters.py +++ b/Examples/Python/sim31_Parameterization/SimulationParameters.py @@ -7,7 +7,7 @@ these parameters on the fly during runtime. from __future__ import print_function import bornagain as ba -from bornagain import deg, angstrom, nm +from bornagain import angstrom, deg, nm, nm2, kvector_t def get_sample(): @@ -15,31 +15,42 @@ def get_sample(): Returns a sample with uncorrelated cylinders and prisms on a substrate. Parameter set is fixed. """ - # defining materials - m_vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) - m_substrate = ba.HomogeneousMaterial("Substrate", 6e-6, 2e-8) - m_particle = ba.HomogeneousMaterial("Particle", 6e-4, 2e-8) - # collection of particles - cylinder_ff = ba.FormFactorCylinder(5*nm, 5*nm) - cylinder = ba.Particle(m_particle, cylinder_ff) - prism_ff = ba.FormFactorPrism3(5*nm, 5*nm) - prism = ba.Particle(m_particle, prism_ff) + # Define materials + material_Particle = ba.HomogeneousMaterial("Particle", 0.0006, 2e-08) + material_Substrate = ba.HomogeneousMaterial("Substrate", 6e-06, 2e-08) + material_Vacuum = ba.HomogeneousMaterial("Vacuum", 0.0, 0.0) + # Define form factors + ff_1 = ba.FormFactorCylinder(5.0*nm, 5.0*nm) + ff_2 = ba.FormFactorPrism3(5.0*nm, 5.0*nm) + + # Define particles + particle_1 = ba.Particle(material_Particle, ff_1) + particle_2 = ba.Particle(material_Particle, ff_2) + + # Define interference functions + iff = ba.InterferenceFunctionNone() + + # Define particle layouts layout = ba.ParticleLayout() - layout.addParticle(cylinder, 0.5) - layout.addParticle(prism, 0.5) - interference = ba.InterferenceFunctionNone() - layout.setInterferenceFunction(interference) - - # vacuum layer with particles and substrate form multi layer - vacuum_layer = ba.Layer(m_vacuum) - vacuum_layer.addLayout(layout) - substrate_layer = ba.Layer(m_substrate, 0) - multi_layer = ba.MultiLayer() - multi_layer.addLayer(vacuum_layer) - multi_layer.addLayer(substrate_layer) - return multi_layer + layout.addParticle(particle_1, 0.5) + layout.addParticle(particle_2, 0.5) + layout.setInterferenceFunction(iff) + layout.setWeight(1) + layout.setTotalParticleSurfaceDensity(0.01) + + # Define layers + layer_1 = ba.Layer(material_Vacuum) + layer_1.addLayout(layout) + layer_2 = ba.Layer(material_Substrate) + + # Define sample + sample = ba.MultiLayer() + sample.addLayer(layer_1) + sample.addLayer(layer_2) + + return sample def get_simulation(): diff --git a/Examples/cpp/modules/FindBornAgain.cmake b/Examples/cpp/modules/FindBornAgain.cmake index 81253fd49a1b1fe7eccc6ab77601b2e4030323ea..e3cf00544e45560cfec863b047485353ec6e5e5c 100644 --- a/Examples/cpp/modules/FindBornAgain.cmake +++ b/Examples/cpp/modules/FindBornAgain.cmake @@ -17,22 +17,20 @@ set(BORNAGAINSYS $ENV{BORNAGAINSYS}) +set(CoreComponents "Base;Param;Sample;Device;Core") if(BORNAGAINSYS) - set(BORNAGAIN_LIBRARY_DIR ${BORNAGAINSYS}/lib/BornAgain-1.6) - set(BORNAGAIN_INCLUDE_DIR ${BORNAGAINSYS}/include/BornAgain-1.6) + set(BORNAGAIN_LIBRARY_DIR ${BORNAGAINSYS}/lib/BornAgain-1.18) + set(BORNAGAIN_INCLUDE_DIR ${BORNAGAINSYS}/include/BornAgain-1.18) endif() -find_library (BORNAGAIN_CORE _libBornAgainCore.so +foreach(lib ${CoreComponents}) + message(STATUS ${lib}) + find_library (BORNAGAIN_${lib} _libBornAgain${lib}.so PATHS ${BORNAGAIN_LIBRARY_DIR} - HINTS ${BORNAGAIN_LIBRARY_DIR} -) - -find_library (BORNAGAIN_FIT _libBornAgainFit.so - PATHS ${BORNAGAIN_LIBRARY_DIR} - HINTS ${BORNAGAIN_LIBRARY_DIR} -) -set(BORNAGAIN_LIBRARIES ${BORNAGAIN_CORE} ${BORNAGAIN_FIT}) + HINTS ${BORNAGAIN_LIBRARY_DIR}) + list(APPEND BORNAGAIN_LIBRARIES ${BORNAGAIN_${lib}}) +endforeach() find_path(BORNAGAIN_INCLUDE_DIR BAVersion.h PATHS /usr/include /usr/local/include /opt/local/include ${BORNAGAIN_INCLUDE_DIR} diff --git a/Sample/Fresnel/MatrixFresnelMap.cpp b/Sample/Fresnel/MatrixFresnelMap.cpp index 4004bbbf5c0d23a1d65ec92c23702c3169b8fa10..f1ba1dc45033bff2f220a1152466606e35fb6f3d 100644 --- a/Sample/Fresnel/MatrixFresnelMap.cpp +++ b/Sample/Fresnel/MatrixFresnelMap.cpp @@ -13,9 +13,9 @@ // ************************************************************************************************ #include "Sample/Fresnel/MatrixFresnelMap.h" +#include "Sample/RT/ILayerRTCoefficients.h" #include "Base/Pixel/SimulationElement.h" #include "Sample/Slice/Slice.h" -#include "Sample/Specular/SpecularMagneticOldStrategy.h" #include <functional> MatrixFresnelMap::MatrixFresnelMap(std::unique_ptr<ISpecularStrategy> strategy) diff --git a/Sample/Fresnel/MatrixFresnelMap.h b/Sample/Fresnel/MatrixFresnelMap.h index 2616af9f5b8fb1915c51c999054a99a0816659f5..1a669e4879fb43ead39ef9dbe38c68a4e95ea622 100644 --- a/Sample/Fresnel/MatrixFresnelMap.h +++ b/Sample/Fresnel/MatrixFresnelMap.h @@ -16,8 +16,6 @@ #define BORNAGAIN_SAMPLE_FRESNEL_MATRIXFRESNELMAP_H #include "Sample/Fresnel/IFresnelMap.h" -#include "Sample/RT/MatrixRTCoefficients.h" -#include "Sample/Specular/SpecularMagneticStrategy.h" #include <cstddef> #include <memory> #include <unordered_map> diff --git a/Sample/RT/MatrixRTCoefficients.cpp b/Sample/RT/MatrixRTCoefficients.cpp index fe1d3181cc6d862a4de858503f9d320c740845db..aeef6194df18ad8d005b7117797d2abc812f112e 100644 --- a/Sample/RT/MatrixRTCoefficients.cpp +++ b/Sample/RT/MatrixRTCoefficients.cpp @@ -2,302 +2,163 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/RT/MatrixRTCoefficients.cpp -//! @brief Implements class MatrixRTCoefficients. +//! @file Sample/RT/MatrixRTCoefficients.cpp +//! @brief Implements class MatrixRTCoefficients. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @copyright Forschungszentrum Jülich GmbH 2020 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ #include "Sample/RT/MatrixRTCoefficients.h" +#include "Base/Utils/Assert.h" + +namespace { +complex_t GetImExponential(complex_t exponent); +const auto eps = std::numeric_limits<double>::epsilon() * 10.; +} // namespace + +MatrixRTCoefficients::MatrixRTCoefficients(double kz_sign, Eigen::Vector2cd eigenvalues, + kvector_t b, double magnetic_SLD) + : m_kz_sign(kz_sign) + , m_lambda(std::move(eigenvalues)) + , m_b(std::move(b)) + , m_magnetic_SLD(magnetic_SLD) { + ASSERT(std::abs(m_b.mag() - 1) < eps || (m_b.mag() < eps && magnetic_SLD < eps)); + + m_T << 1, 0, 0, 1; + m_R << -1, 0, 0, -1; +} + +MatrixRTCoefficients::MatrixRTCoefficients(const MatrixRTCoefficients& other) = default; + +MatrixRTCoefficients::~MatrixRTCoefficients() = default; MatrixRTCoefficients* MatrixRTCoefficients::clone() const { return new MatrixRTCoefficients(*this); } +Eigen::Matrix2cd MatrixRTCoefficients::TransformationMatrix(Eigen::Vector2d selection) const { + const Eigen::Matrix2cd exp2 = Eigen::DiagonalMatrix<complex_t, 2>(selection); + + if (std::abs(m_b.mag() - 1.) < eps) { + Eigen::Matrix2cd Q; + const double factor1 = 2. * (1. + m_b.z()); + Q << (1. + m_b.z()), (I * m_b.y() - m_b.x()), (m_b.x() + I * m_b.y()), (m_b.z() + 1.); + return Q * exp2 * Q.adjoint() / factor1; + + } else if (m_b.mag() < eps) + return exp2; + + throw std::runtime_error("Broken magnetic field vector"); +} + +Eigen::Matrix2cd MatrixRTCoefficients::T1Matrix() const { + return TransformationMatrix({0., 1.}); +} + +Eigen::Matrix2cd MatrixRTCoefficients::T2Matrix() const { + return TransformationMatrix({1., 0.}); +} + Eigen::Vector2cd MatrixRTCoefficients::T1plus() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = T1m * phi_psi_plus; - result(0) = m(2); - result(1) = m(3); - if (lambda(0) == 0.0 && result == Eigen::Vector2cd::Zero()) - result(0) = 0.5; - return result; + return T1Matrix() * m_T.col(0); } Eigen::Vector2cd MatrixRTCoefficients::R1plus() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = R1m * phi_psi_plus; - result(0) = m(2); - result(1) = m(3); - Eigen::Matrix<complex_t, 4, 1> mT = T1m * phi_psi_plus; - if (lambda(0) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) - result(0) = -0.5; - return result; + return T1Matrix() * m_R.col(0); } Eigen::Vector2cd MatrixRTCoefficients::T2plus() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = T2m * phi_psi_plus; - result(0) = m(2); - result(1) = m(3); - if (lambda(1) == 0.0 && result == Eigen::Vector2cd::Zero()) - result(0) = 0.5; - return result; + return T2Matrix() * m_T.col(0); } Eigen::Vector2cd MatrixRTCoefficients::R2plus() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = R2m * phi_psi_plus; - result(0) = m(2); - result(1) = m(3); - Eigen::Matrix<complex_t, 4, 1> mT = T2m * phi_psi_plus; - if (lambda(1) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) - result(0) = -0.5; - return result; + return T2Matrix() * m_R.col(0); } Eigen::Vector2cd MatrixRTCoefficients::T1min() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = T1m * phi_psi_min; - result(0) = m(2); - result(1) = m(3); - if (lambda(0) == 0.0 && result == Eigen::Vector2cd::Zero()) - result(1) = 0.5; - return result; + return T1Matrix() * m_T.col(1); } Eigen::Vector2cd MatrixRTCoefficients::R1min() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = R1m * phi_psi_min; - result(0) = m(2); - result(1) = m(3); - Eigen::Matrix<complex_t, 4, 1> mT = T1m * phi_psi_min; - if (lambda(0) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) - result(1) = -0.5; - return result; + return T1Matrix() * m_R.col(1); } Eigen::Vector2cd MatrixRTCoefficients::T2min() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = T2m * phi_psi_min; - result(0) = m(2); - result(1) = m(3); - if (lambda(1) == 0.0 && result == Eigen::Vector2cd::Zero()) - result(1) = 0.5; - return result; + return T2Matrix() * m_T.col(1); } Eigen::Vector2cd MatrixRTCoefficients::R2min() const { - Eigen::Vector2cd result; - Eigen::Matrix<complex_t, 4, 1> m = R2m * phi_psi_min; - result(0) = m(2); - result(1) = m(3); - Eigen::Matrix<complex_t, 4, 1> mT = T2m * phi_psi_min; - if (lambda(1) == 0.0 && mT(2) == 0.0 && mT(3) == 0.0) - result(1) = -0.5; + return T2Matrix() * m_R.col(1); +} + +Eigen::Vector2cd MatrixRTCoefficients::getKz() const { + return m_kz_sign * m_lambda; +} + +Eigen::Matrix2cd MatrixRTCoefficients::pMatrixHelper(double sign) const { + const complex_t alpha = m_lambda(1) + m_lambda(0); + const complex_t beta = m_lambda(1) - m_lambda(0); + + Eigen::Matrix2cd result; + + kvector_t b = m_b; + + result << alpha + sign * beta * b.z(), sign * beta * (b.x() - I * b.y()), + sign * beta * (b.x() + I * b.y()), alpha - sign * beta * b.z(); + + return m_kz_sign * result; +} + +Eigen::Matrix2cd MatrixRTCoefficients::computeP() const { + Eigen::Matrix2cd result = pMatrixHelper(1.); + result *= 0.5; + return result; } -void MatrixRTCoefficients::calculateTRMatrices() { - if (m_b_mag == 0.0) { - calculateTRWithoutMagnetization(); - return; - } - - if (lambda(0) == 0.0) { - complex_t ikt = mul_I(m_kt); - // Lambda1 component contained only in T1m (R1m=0) - // row 0: - T1m(0, 0) = (1.0 - m_bz / m_b_mag) / 2.0; - T1m(0, 1) = -m_scatt_matrix(0, 1) / 2.0 / m_b_mag; - // row 1: - T1m(1, 0) = -m_scatt_matrix(1, 0) / 2.0 / m_b_mag; - T1m(1, 1) = (1.0 + m_bz / m_b_mag) / 2.0; - // row 2: - T1m(2, 0) = ikt * (1.0 - m_bz / m_b_mag) / 2.0; - T1m(2, 1) = -ikt * m_scatt_matrix(0, 1) / 2.0 / m_b_mag; - T1m(2, 2) = T1m(0, 0); - T1m(2, 3) = T1m(0, 1); - // row 3: - T1m(3, 0) = -ikt * m_scatt_matrix(1, 0) / 2.0 / m_b_mag; - T1m(3, 1) = ikt * (1.0 + m_bz / m_b_mag) / 2.0; - T1m(3, 2) = T1m(1, 0); - T1m(3, 3) = T1m(1, 1); - } else { - // 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); - } - - if (lambda(1) == 0.0) { - complex_t ikt = mul_I(m_kt); - // Lambda2 component contained only in T2m (R2m=0) - // row 0: - T2m(0, 0) = (1.0 + m_bz / m_b_mag) / 2.0; - T2m(0, 1) = m_scatt_matrix(0, 1) / 2.0 / m_b_mag; - // row 1: - T2m(1, 0) = m_scatt_matrix(1, 0) / 2.0 / m_b_mag; - T2m(1, 1) = (1.0 - m_bz / m_b_mag) / 2.0; - // row 2: - T2m(2, 0) = ikt * (1.0 + m_bz / m_b_mag) / 2.0; - T2m(2, 1) = ikt * m_scatt_matrix(0, 1) / 2.0 / m_b_mag; - T2m(2, 2) = T2m(0, 0); - T2m(2, 3) = T2m(0, 1); - // row 3: - T2m(3, 0) = ikt * m_scatt_matrix(1, 0) / 2.0 / m_b_mag; - T2m(3, 1) = ikt * (1.0 - m_bz / m_b_mag) / 2.0; - T2m(3, 2) = T2m(1, 0); - T2m(3, 3) = T2m(1, 1); - } else { - // 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); - } +Eigen::Matrix2cd MatrixRTCoefficients::computeInverseP() const { + const complex_t alpha = m_lambda(1) + m_lambda(0); + const complex_t beta = m_lambda(1) - m_lambda(0); + + if (std::abs(alpha * alpha - beta * beta) == 0.) + return Eigen::Matrix2cd::Zero(); + + Eigen::Matrix2cd result = pMatrixHelper(-1.); + result *= 2. / (alpha * alpha - beta * beta); + + return result; } -void MatrixRTCoefficients::calculateTRWithoutMagnetization() { - T1m.setZero(); - R1m.setZero(); - T2m.setZero(); - R2m.setZero(); - - if (m_a == 0.0) { - // Spin down component contained only in T1 (R1=0) - T1m(1, 1) = 1.0; - T1m(3, 1) = mul_I(m_kt); - T1m(3, 3) = 1.0; - - // Spin up component contained only in T2 (R2=0) - T2m(0, 0) = 1.0; - T2m(2, 0) = mul_I(m_kt); - T2m(2, 2) = 1.0; - return; - } - - // T1m: - 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(1, 1) = 0.5; - R1m(1, 3) = std::sqrt(m_a) / 2.0; - R1m(3, 1) = 1.0 / (2.0 * std::sqrt(m_a)); - R1m(3, 3) = 0.5; - - // T2m: - T2m(0, 0) = 0.5; - T2m(0, 2) = -std::sqrt(m_a) / 2.0; - T2m(2, 0) = -1.0 / (2.0 * std::sqrt(m_a)); - T2m(2, 2) = 0.5; - - // R2m: - 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; +Eigen::Matrix2cd MatrixRTCoefficients::computeDeltaMatrix(double thickness) { + Eigen::Matrix2cd result; + const complex_t alpha = 0.5 * thickness * (m_lambda(1) + m_lambda(0)); + + const Eigen::Matrix2cd exp2 = Eigen::DiagonalMatrix<complex_t, 2>( + {GetImExponential(m_kz_sign * thickness * m_lambda(1)), + GetImExponential(m_kz_sign * thickness * m_lambda(0))}); + + // Compute resulting phase matrix according to exp(i p_m d_m) = exp1 * Q * exp2 * Q.adjoint(); + if (std::abs(m_b.mag() - 1.) < eps) { + Eigen::Matrix2cd Q; + const double factor1 = 2. * (1. + m_b.z()); + Q << (1. + m_b.z()), (I * m_b.y() - m_b.x()), (m_b.x() + I * m_b.y()), (m_b.z() + 1.); + + return Q * exp2 * Q.adjoint() / factor1; + + } else if (m_b.mag() < eps) + return Eigen::Matrix2cd::Identity() * GetImExponential(m_kz_sign * alpha); + + throw std::runtime_error("Broken magnetic field vector"); } -void MatrixRTCoefficients::initializeBottomLayerPhiPsi() { - if (m_b_mag == 0.0) { - phi_psi_min << 0.0, -std::sqrt(m_a), 0.0, 1.0; - phi_psi_plus << -std::sqrt(m_a), 0.0, 1.0, 0.0; - return; - } - // First basis vector that has no upward going wave amplitude - phi_psi_min(0) = m_scatt_matrix(0, 1) * (lambda(0) - lambda(1)) / 2.0 / m_b_mag; - phi_psi_min(1) = (m_bz * (lambda(1) - lambda(0)) / m_b_mag - lambda(1) - lambda(0)) / 2.0; - phi_psi_min(2) = 0.0; - phi_psi_min(3) = 1.0; - - // Second basis vector that has no upward going wave amplitude - phi_psi_plus(0) = -(m_scatt_matrix(0, 0) + lambda(0) * lambda(1)) / (lambda(0) + lambda(1)); - phi_psi_plus(1) = m_scatt_matrix(1, 0) * (lambda(0) - lambda(1)) / 2.0 / m_b_mag; - phi_psi_plus(2) = 1.0; - phi_psi_plus(3) = 0.0; +namespace { +complex_t GetImExponential(complex_t exponent) { + if (exponent.imag() > -std::log(std::numeric_limits<double>::min())) + return 0.0; + return std::exp(I * exponent); } +} // namespace diff --git a/Sample/RT/MatrixRTCoefficients.h b/Sample/RT/MatrixRTCoefficients.h index 964a47d8a351c6be53befa459680d852dfe28262..0f467eda100970224f81c3a690803f87f488ee78 100644 --- a/Sample/RT/MatrixRTCoefficients.h +++ b/Sample/RT/MatrixRTCoefficients.h @@ -2,12 +2,12 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/RT/MatrixRTCoefficients.h +//! @file Sample/RT/MatrixRTCoefficients.h //! @brief Defines class MatrixRTCoefficients. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @copyright Forschungszentrum Jülich GmbH 2020 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ @@ -15,55 +15,63 @@ #ifndef BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_H #define BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_H +#include "Base/Vector/Vectors3D.h" #include "Sample/RT/ILayerRTCoefficients.h" +#include <vector> //! Specular reflection and transmission coefficients in a layer in case -//! of 2x2 matrix interactions between the layers and the scattered particle. +//! of magnetic interactions between the scattered particle and the layer. //! @ingroup algorithms_internal class MatrixRTCoefficients : public ILayerRTCoefficients { public: - MatrixRTCoefficients() : m_kt(0.0) {} - virtual ~MatrixRTCoefficients() {} + friend class SpecularMagneticStrategy; + friend class SpecularMagneticNCStrategy; + friend class SpecularMagneticTanhStrategy; - virtual MatrixRTCoefficients* clone() const; + MatrixRTCoefficients(double kz_sign, Eigen::Vector2cd eigenvalues, kvector_t b, + double magnetic_SLD); + MatrixRTCoefficients(const MatrixRTCoefficients& other); + ~MatrixRTCoefficients() override; + + MatrixRTCoefficients* clone() const override; //! The following functions return the transmitted and reflected amplitudes //! for different incoming beam polarizations and eigenmodes - virtual Eigen::Vector2cd T1plus() const; - virtual Eigen::Vector2cd R1plus() const; - virtual Eigen::Vector2cd T2plus() const; - virtual Eigen::Vector2cd R2plus() const; - virtual Eigen::Vector2cd T1min() const; - virtual Eigen::Vector2cd R1min() const; - virtual Eigen::Vector2cd T2min() const; - virtual Eigen::Vector2cd R2min() const; + Eigen::Vector2cd T1plus() const override; + Eigen::Vector2cd R1plus() const override; + Eigen::Vector2cd T2plus() const override; + Eigen::Vector2cd R2plus() const override; + Eigen::Vector2cd T1min() const override; + Eigen::Vector2cd R1min() const override; + Eigen::Vector2cd T2min() const override; + Eigen::Vector2cd R2min() const override; //! Returns z-part of the two wavevector eigenmodes - virtual Eigen::Vector2cd getKz() const { return kz; } + Eigen::Vector2cd getKz() const override; + double magneticSLD() const { return m_magnetic_SLD; } + + Eigen::Matrix2cd computeP() const; + Eigen::Matrix2cd computeInverseP() const; + + Eigen::Matrix2cd computeDeltaMatrix(double thickness); + + Eigen::Matrix2cd getReflectionMatrix() const override { return m_R; }; + +private: + double m_kz_sign; //! wave propagation direction (-1 for direct one, 1 for time reverse) + Eigen::Vector2cd m_lambda; //!< eigenvalues for wave propagation + kvector_t m_b; //!< unit magnetic field vector + double m_magnetic_SLD; + + Eigen::Matrix2cd m_T; + Eigen::Matrix2cd m_R; - void calculateTRMatrices(); - void calculateTRWithoutMagnetization(); - void initializeBottomLayerPhiPsi(); + // helper functions to compute DWBA compatible amplitudes used in the T1plus() etc. functions + Eigen::Matrix2cd TransformationMatrix(Eigen::Vector2d selection) const; + Eigen::Matrix2cd T1Matrix() const; + Eigen::Matrix2cd T2Matrix() const; - // NOTE: exceptionally, this class has member variables without prefix m_ - Eigen::Vector2cd kz; //!< z-part of the two wavevector eigenmodes - Eigen::Vector2cd lambda; //!< positive eigenvalues of transfer matrix - Eigen::Vector4cd phi_psi_plus; //!< boundary values for up-polarization - Eigen::Vector4cd phi_psi_min; //!< boundary values for down-polarization - Eigen::Matrix4cd T1m; //!< matrix selecting the transmitted part of - //!< the first eigenmode - Eigen::Matrix4cd R1m; //!< matrix selecting the reflected part of - //!< the first eigenmode - Eigen::Matrix4cd T2m; //!< matrix selecting the transmitted part of - //!< the second eigenmode - Eigen::Matrix4cd R2m; //!< matrix selecting the reflected part of - //!< the second eigenmode - Eigen::Matrix2cd m_scatt_matrix; //!< scattering matrix - complex_t m_a; //!< polarization independent part of scattering matrix - complex_t m_b_mag; //!< magnitude of magnetic interaction term - complex_t m_bz; //!< z-part of magnetic interaction term - double m_kt; //!< wavevector length times thickness of layer for use when - //!< lambda=0 + Eigen::Matrix2cd pMatrixHelper(double sign) const; }; #endif // BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_H diff --git a/Sample/RT/MatrixRTCoefficients_v3.cpp b/Sample/RT/MatrixRTCoefficients_v3.cpp deleted file mode 100644 index 0e3ccbf5bbd659907c7acbeaf70d9a7851e76957..0000000000000000000000000000000000000000 --- a/Sample/RT/MatrixRTCoefficients_v3.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file Sample/RT/MatrixRTCoefficients_v3.cpp -//! @brief Implements class MatrixRTCoefficients_v3. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2020 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#include "Sample/RT/MatrixRTCoefficients_v3.h" -#include "Base/Utils/Assert.h" - -namespace { -complex_t GetImExponential(complex_t exponent); -const auto eps = std::numeric_limits<double>::epsilon() * 10.; -} // namespace - -MatrixRTCoefficients_v3::MatrixRTCoefficients_v3(double kz_sign, Eigen::Vector2cd eigenvalues, - kvector_t b, double magnetic_SLD) - : m_kz_sign(kz_sign) - , m_lambda(std::move(eigenvalues)) - , m_b(std::move(b)) - , m_magnetic_SLD(magnetic_SLD) { - ASSERT(std::abs(m_b.mag() - 1) < eps || (m_b.mag() < eps && magnetic_SLD < eps)); - - m_T << 1, 0, 0, 1; - m_R << -1, 0, 0, -1; -} - -MatrixRTCoefficients_v3::MatrixRTCoefficients_v3(const MatrixRTCoefficients_v3& other) = default; - -MatrixRTCoefficients_v3::~MatrixRTCoefficients_v3() = default; - -MatrixRTCoefficients_v3* MatrixRTCoefficients_v3::clone() const { - return new MatrixRTCoefficients_v3(*this); -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::TransformationMatrix(Eigen::Vector2d selection) const { - const Eigen::Matrix2cd exp2 = Eigen::DiagonalMatrix<complex_t, 2>(selection); - - if (std::abs(m_b.mag() - 1.) < eps) { - Eigen::Matrix2cd Q; - const double factor1 = 2. * (1. + m_b.z()); - Q << (1. + m_b.z()), (I * m_b.y() - m_b.x()), (m_b.x() + I * m_b.y()), (m_b.z() + 1.); - return Q * exp2 * Q.adjoint() / factor1; - - } else if (m_b.mag() < eps) - return exp2; - - throw std::runtime_error("Broken magnetic field vector"); -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::T1Matrix() const { - return TransformationMatrix({0., 1.}); -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::T2Matrix() const { - return TransformationMatrix({1., 0.}); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::T1plus() const { - return T1Matrix() * m_T.col(0); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::R1plus() const { - return T1Matrix() * m_R.col(0); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::T2plus() const { - return T2Matrix() * m_T.col(0); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::R2plus() const { - return T2Matrix() * m_R.col(0); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::T1min() const { - return T1Matrix() * m_T.col(1); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::R1min() const { - return T1Matrix() * m_R.col(1); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::T2min() const { - return T2Matrix() * m_T.col(1); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::R2min() const { - return T2Matrix() * m_R.col(1); -} - -Eigen::Vector2cd MatrixRTCoefficients_v3::getKz() const { - return m_kz_sign * m_lambda; -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::pMatrixHelper(double sign) const { - const complex_t alpha = m_lambda(1) + m_lambda(0); - const complex_t beta = m_lambda(1) - m_lambda(0); - - Eigen::Matrix2cd result; - - kvector_t b = m_b; - - result << alpha + sign * beta * b.z(), sign * beta * (b.x() - I * b.y()), - sign * beta * (b.x() + I * b.y()), alpha - sign * beta * b.z(); - - return result; -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::computeP() const { - Eigen::Matrix2cd result = pMatrixHelper(1.); - result *= 0.5; - - return result; -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::computeInverseP() const { - const complex_t alpha = m_lambda(1) + m_lambda(0); - const complex_t beta = m_lambda(1) - m_lambda(0); - - if (std::abs(alpha * alpha - beta * beta) == 0.) - return Eigen::Matrix2cd::Zero(); - - Eigen::Matrix2cd result = pMatrixHelper(-1.); - result *= 2. / (alpha * alpha - beta * beta); - - return result; -} - -Eigen::Matrix2cd MatrixRTCoefficients_v3::computeDeltaMatrix(double thickness) { - Eigen::Matrix2cd result; - const complex_t alpha = 0.5 * thickness * (m_lambda(1) + m_lambda(0)); - - const Eigen::Matrix2cd exp2 = Eigen::DiagonalMatrix<complex_t, 2>( - {GetImExponential(thickness * m_lambda(1)), GetImExponential(thickness * m_lambda(0))}); - - // Compute resulting phase matrix according to exp(i p_m d_m) = exp1 * Q * exp2 * Q.adjoint(); - if (std::abs(m_b.mag() - 1.) < eps) { - Eigen::Matrix2cd Q; - const double factor1 = 2. * (1. + m_b.z()); - Q << (1. + m_b.z()), (I * m_b.y() - m_b.x()), (m_b.x() + I * m_b.y()), (m_b.z() + 1.); - - return Q * exp2 * Q.adjoint() / factor1; - - } else if (m_b.mag() < eps) - return Eigen::Matrix2cd::Identity() * GetImExponential(alpha); - - throw std::runtime_error("Broken magnetic field vector"); -} - -namespace { -complex_t GetImExponential(complex_t exponent) { - if (exponent.imag() > -std::log(std::numeric_limits<double>::min())) - return 0.0; - return std::exp(I * exponent); -} -} // namespace diff --git a/Sample/RT/MatrixRTCoefficients_v3.h b/Sample/RT/MatrixRTCoefficients_v3.h deleted file mode 100644 index 7a239c1f011c2c589561cef9b6c51062f755ff39..0000000000000000000000000000000000000000 --- a/Sample/RT/MatrixRTCoefficients_v3.h +++ /dev/null @@ -1,82 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file Sample/RT/MatrixRTCoefficients_v3.h -//! @brief Defines class MatrixRTCoefficients_v3. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2020 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#ifndef BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_V3_H -#define BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_V3_H - -#include "Base/Vector/Vectors3D.h" -#include "Sample/RT/ILayerRTCoefficients.h" -#include <vector> - -//! Specular reflection and transmission coefficients in a layer in case -//! of magnetic interactions between the scattered particle and the layer. -//! @ingroup algorithms_internal - -class MatrixRTCoefficients_v3 : public ILayerRTCoefficients { -public: - friend class SpecularMagneticNewStrategy; - friend class SpecularMagneticNewNCStrategy; - friend class SpecularMagneticNewNCTestingStrategy; - friend class SpecularMagneticNewTanhStrategy; - friend class SpecularMagnetic_v3ConsistencyTest; - friend class SpecularMagnetic_v3ConsistencyTest_ScalarMagneticAmplitudes_Test; - friend class SpecularMagnetic_v3ConsistencyTest_AmplitudesBackwardsBackwards_Test; - template <class sampleClass> friend class TestSimulation; - - MatrixRTCoefficients_v3(double kz_sign, Eigen::Vector2cd eigenvalues, kvector_t b, - double magnetic_SLD); - MatrixRTCoefficients_v3(const MatrixRTCoefficients_v3& other); - ~MatrixRTCoefficients_v3() override; - - MatrixRTCoefficients_v3* clone() const override; - - //! The following functions return the transmitted and reflected amplitudes - //! for different incoming beam polarizations and eigenmodes - Eigen::Vector2cd T1plus() const override; - Eigen::Vector2cd R1plus() const override; - Eigen::Vector2cd T2plus() const override; - Eigen::Vector2cd R2plus() const override; - Eigen::Vector2cd T1min() const override; - Eigen::Vector2cd R1min() const override; - Eigen::Vector2cd T2min() const override; - Eigen::Vector2cd R2min() const override; - //! Returns z-part of the two wavevector eigenmodes - Eigen::Vector2cd getKz() const override; - double magneticSLD() const { return m_magnetic_SLD; } - - Eigen::Matrix2cd computeP() const; - Eigen::Matrix2cd computeInverseP() const; - - Eigen::Matrix2cd computeDeltaMatrix(double thickness); - - Eigen::Matrix2cd getReflectionMatrix() const override { return m_R; }; - -private: - double m_kz_sign; //! wave propagation direction (-1 for direct one, 1 for time reverse) - Eigen::Vector2cd m_lambda; //!< eigenvalues for wave propagation - kvector_t m_b; //!< unit magnetic field vector - double m_magnetic_SLD; - - Eigen::Matrix2cd m_T; - Eigen::Matrix2cd m_R; - - // helper functions to compute DWBA compatible amplitudes used in the T1plus() etc. functions - Eigen::Matrix2cd TransformationMatrix(Eigen::Vector2d selection) const; - Eigen::Matrix2cd T1Matrix() const; - Eigen::Matrix2cd T2Matrix() const; - - Eigen::Matrix2cd pMatrixHelper(double sign) const; -}; - -#endif // BORNAGAIN_SAMPLE_RT_MATRIXRTCOEFFICIENTS_V3_H diff --git a/Sample/Specular/SpecularMagneticNewNCStrategy.cpp b/Sample/Specular/SpecularMagneticNCStrategy.cpp similarity index 89% rename from Sample/Specular/SpecularMagneticNewNCStrategy.cpp rename to Sample/Specular/SpecularMagneticNCStrategy.cpp index 5fd3633ac4ff66eab9e94a8769f82da7530561c2..85746b1327d6c4af8600f0ecabf4d01f06e68cbc 100644 --- a/Sample/Specular/SpecularMagneticNewNCStrategy.cpp +++ b/Sample/Specular/SpecularMagneticNCStrategy.cpp @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/Specular/SpecularMagneticNewNCStrategy.cpp -//! @brief Implements class SpecularMagneticNewNCStrategy. +//! @file Sample/Specular/SpecularMagneticNCStrategy.cpp +//! @brief Implements class SpecularMagneticNCStrategy. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,15 +12,15 @@ // // ************************************************************************************************ -#include "Sample/Specular/SpecularMagneticNewNCStrategy.h" +#include "Sample/Specular/SpecularMagneticNCStrategy.h" namespace { complex_t checkForUnderflow(complex_t val); } std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> -SpecularMagneticNewNCStrategy::computeRoughnessMatrices(const MatrixRTCoefficients_v3& coeff_i, - const MatrixRTCoefficients_v3& coeff_i1, +SpecularMagneticNCStrategy::computeRoughnessMatrices(const MatrixRTCoefficients& coeff_i, + const MatrixRTCoefficients& coeff_i1, double sigma) const { complex_t beta_i = coeff_i.m_lambda(1) - coeff_i.m_lambda(0); complex_t beta_i1 = coeff_i1.m_lambda(1) - coeff_i1.m_lambda(0); @@ -65,8 +65,8 @@ SpecularMagneticNewNCStrategy::computeRoughnessMatrices(const MatrixRTCoefficien } std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> -SpecularMagneticNewNCStrategy::computeBackwardsSubmatrices(const MatrixRTCoefficients_v3& coeff_i, - const MatrixRTCoefficients_v3& coeff_i1, +SpecularMagneticNCStrategy::computeBackwardsSubmatrices(const MatrixRTCoefficients& coeff_i, + const MatrixRTCoefficients& coeff_i1, double sigma) const { Eigen::Matrix2cd roughness_sum{Eigen::Matrix2cd::Identity()}; Eigen::Matrix2cd roughness_diff{Eigen::Matrix2cd::Identity()}; diff --git a/Sample/Specular/SpecularMagneticNewNCStrategy.h b/Sample/Specular/SpecularMagneticNCStrategy.h similarity index 59% rename from Sample/Specular/SpecularMagneticNewNCStrategy.h rename to Sample/Specular/SpecularMagneticNCStrategy.h index 66d402287521912e9bd4f42ce3f3a346829ed5e4..573c5b9e7a322dd09705f8694beb526aa29b49af 100644 --- a/Sample/Specular/SpecularMagneticNewNCStrategy.h +++ b/Sample/Specular/SpecularMagneticNCStrategy.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/Specular/SpecularMagneticNewNCStrategy.h -//! @brief Defines class SpecularMagneticNewNCStrategy. +//! @file Sample/Specular/SpecularMagneticNCStrategy.h +//! @brief Defines class SpecularMagneticNCStrategy. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,10 +12,10 @@ // // ************************************************************************************************ -#ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWNCSTRATEGY_H -#define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWNCSTRATEGY_H +#ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNCSTRATEGY_H +#define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNCSTRATEGY_H -#include "Sample/Specular/SpecularMagneticNewStrategy.h" +#include "Sample/Specular/SpecularMagneticStrategy.h" #include <memory> #include <vector> @@ -27,15 +27,15 @@ //! document "Polarized Implementation of the Transfer Matrix Method" //! //! @ingroup algorithms_internal -class SpecularMagneticNewNCStrategy : public SpecularMagneticNewStrategy { +class SpecularMagneticNCStrategy : public SpecularMagneticStrategy { private: std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> - computeRoughnessMatrices(const MatrixRTCoefficients_v3& coeff_i, - const MatrixRTCoefficients_v3& coeff_i1, double sigma) const; + computeRoughnessMatrices(const MatrixRTCoefficients& coeff_i, + const MatrixRTCoefficients& coeff_i1, double sigma) const; virtual std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> - computeBackwardsSubmatrices(const MatrixRTCoefficients_v3& coeff_i, - const MatrixRTCoefficients_v3& coeff_i1, double sigma) const; + computeBackwardsSubmatrices(const MatrixRTCoefficients& coeff_i, + const MatrixRTCoefficients& coeff_i1, double sigma) const; }; -#endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWNCSTRATEGY_H +#endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNCSTRATEGY_H diff --git a/Sample/Specular/SpecularMagneticNewStrategy.cpp b/Sample/Specular/SpecularMagneticNewStrategy.cpp deleted file mode 100644 index cb71ab7c766222053a34063244e123d5c65eadbd..0000000000000000000000000000000000000000 --- a/Sample/Specular/SpecularMagneticNewStrategy.cpp +++ /dev/null @@ -1,183 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file Sample/Specular/SpecularMagneticNewStrategy.cpp -//! @brief Implements class SpecularMagneticNewStrategy. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2020 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#include "Sample/Specular/SpecularMagneticNewStrategy.h" -#include "Base/Const/PhysicalConstants.h" -#include "Sample/Slice/KzComputation.h" -#include "Sample/Slice/LayerRoughness.h" -#include "Sample/Slice/Slice.h" - -namespace { -double magneticSLD(kvector_t B_field); -Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag); -Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs); - -// The factor 1e-18 is here to have unit: 1/T*nm^-2 -constexpr double magnetic_prefactor = PhysConsts::m_n * PhysConsts::g_factor_n * PhysConsts::mu_N - / PhysConsts::h_bar / PhysConsts::h_bar / 4. / M_PI * 1e-18; -const auto eps = std::numeric_limits<double>::epsilon() * 10.; -const LayerRoughness* GetBottomRoughness(const std::vector<Slice>& slices, - const size_t slice_index); -} // namespace - -ISpecularStrategy::coeffs_t SpecularMagneticNewStrategy::Execute(const std::vector<Slice>& slices, - const kvector_t& k) const { - return Execute(slices, KzComputation::computeReducedKz(slices, k)); -} - -ISpecularStrategy::coeffs_t -SpecularMagneticNewStrategy::Execute(const std::vector<Slice>& slices, - const std::vector<complex_t>& kz) const { - if (slices.size() != kz.size()) - throw std::runtime_error("Number of slices does not match the size of the kz-vector"); - - ISpecularStrategy::coeffs_t result; - for (auto& coeff : computeTR(slices, kz)) - result.push_back(std::make_unique<MatrixRTCoefficients_v3>(coeff)); - - return result; -} - -std::vector<MatrixRTCoefficients_v3> -SpecularMagneticNewStrategy::computeTR(const std::vector<Slice>& slices, - const std::vector<complex_t>& kzs) const { - const size_t N = slices.size(); - - if (slices.size() != kzs.size()) - throw std::runtime_error( - "Error in SpecularMagnetic_::execute: kz vector and slices size shall coinside."); - if (slices.empty()) - return {}; - - std::vector<MatrixRTCoefficients_v3> result; - result.reserve(N); - - const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0; // save sign to restore it later - - auto B_0 = slices.front().bField(); - result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0}, 0.0); - for (size_t i = 1, size = slices.size(); i < size; ++i) { - auto B = slices[i].bField() - B_0; - auto magnetic_SLD = magneticSLD(B); - result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)), - B.mag() > eps ? B / B.mag() : kvector_t{0.0, 0.0, 0.0}, magnetic_SLD); - } - - if (N == 1) { - result[0].m_T = Eigen::Matrix2cd::Identity(); - result[0].m_R = Eigen::Matrix2cd::Zero(); - return result; - - } else if (kzs[0] == 0.) { - result[0].m_T = Eigen::Matrix2cd::Identity(); - result[0].m_R = -Eigen::Matrix2cd::Identity(); - for (size_t i = 1; i < N; ++i) { - result[i].m_T.setZero(); - result[i].m_R.setZero(); - } - return result; - } - - calculateUpwards(result, slices); - - return result; -} - -void SpecularMagneticNewStrategy::calculateUpwards(std::vector<MatrixRTCoefficients_v3>& coeff, - const std::vector<Slice>& slices) const { - const auto N = slices.size(); - std::vector<Eigen::Matrix2cd> SMatrices(N - 1); - std::vector<complex_t> Normalization(N - 1); - - // bottom boundary condition - coeff.back().m_T = Eigen::Matrix2cd::Identity(); - coeff.back().m_R = Eigen::Matrix2cd::Zero(); - - for (int i = N - 2; i >= 0; --i) { - double sigma = 0.; - if (const auto roughness = GetBottomRoughness(slices, i)) - sigma = roughness->getSigma(); - - // compute the 2x2 submatrices in the write-up denoted as P+, P- and delta - const auto mpmm = computeBackwardsSubmatrices(coeff[i], coeff[i + 1], sigma); - const Eigen::Matrix2cd mp = mpmm.first; - const Eigen::Matrix2cd mm = mpmm.second; - - const Eigen::Matrix2cd delta = coeff[i].computeDeltaMatrix(slices[i].thickness()); - - // compute the rotation matrix - Eigen::Matrix2cd S, Si; - Si = mp + mm * coeff[i + 1].m_R; - S << Si(1, 1), -Si(0, 1), -Si(1, 0), Si(0, 0); - const complex_t norm = S(0, 0) * S(1, 1) - S(0, 1) * S(1, 0); - S = S * delta; - - // store the rotation matrix and normalization constant in order to rotate - // the coefficients for all lower slices at the end of the computation - SMatrices[i] = S; - Normalization[i] = norm; - - // compute the reflection matrix and - // rotate the polarization such that we have pure incoming states (T = I) - S /= norm; - - // T is always equal to the identity at this point, no need to store - coeff[i].m_R = delta * (mm + mp * coeff[i + 1].m_R) * S; - } - - // now correct all amplitudes in forward direction by dividing with the remaining - // normalization constants. In addition rotate the polarization by the amount - // that was rotated above the current interface - // if the normalization overflows, all amplitudes below that point are set to zero - complex_t dumpingFactor = 1; - Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity(); - for (size_t i = 1; i < N; ++i) { - dumpingFactor = dumpingFactor * Normalization[i - 1]; - S = SMatrices[i - 1] * S; - - if (std::isinf(std::norm(dumpingFactor))) { - std::for_each(coeff.begin() + i, coeff.end(), [](auto& coeff) { - coeff.m_T = Eigen::Matrix2cd::Zero(); - coeff.m_R = Eigen::Matrix2cd::Zero(); - }); - break; - } - - coeff[i].m_T = S / dumpingFactor; // T * S omitted, since T is always I - coeff[i].m_R *= S / dumpingFactor; - } -} - -namespace { -double magneticSLD(kvector_t B_field) { - return magnetic_prefactor * B_field.mag(); -} - -Eigen::Vector2cd eigenvalues(complex_t kz, double magnetic_SLD) { - const complex_t a = kz * kz; - return {std::sqrt(a - 4. * M_PI * magnetic_SLD), std::sqrt(a + 4. * M_PI * magnetic_SLD)}; -} - -Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs) { - auto lambda = [](complex_t value) { return std::abs(value) < 1e-40 ? 1e-40 : value; }; - return {lambda(eigenvs(0)), lambda(eigenvs(1))}; -} - -const LayerRoughness* GetBottomRoughness(const std::vector<Slice>& slices, - const size_t slice_index) { - if (slice_index + 1 < slices.size()) - return slices[slice_index + 1].topRoughness(); - return nullptr; -} -} // namespace diff --git a/Sample/Specular/SpecularMagneticNewStrategy.h b/Sample/Specular/SpecularMagneticNewStrategy.h deleted file mode 100644 index fc7e85f3afcee0b1061bfb2cbe43acff2f5991f1..0000000000000000000000000000000000000000 --- a/Sample/Specular/SpecularMagneticNewStrategy.h +++ /dev/null @@ -1,56 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file Sample/Specular/SpecularMagneticNewStrategy.h -//! @brief Defines class SpecularMagneticNewStrategy. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2020 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWSTRATEGY_H -#define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWSTRATEGY_H - -#include "Sample/RT/MatrixRTCoefficients_v3.h" -#include "Sample/Specular/ISpecularStrategy.h" -#include <memory> -#include <vector> - -class Slice; - -//! Implements the magnetic Fresnel computation with Nevot-Croce roughness -//! -//! Implements the transfer matrix formalism for the calculation of wave -//! amplitudes of the coherent wave solution in a multilayer with magnetization. -//! For a description, see internal -//! document "Polarized Implementation of the Transfer Matrix Method" -//! -//! @ingroup algorithms_internal -class SpecularMagneticNewStrategy : public ISpecularStrategy { -public: - //! Computes refraction angle reflection/transmission coefficients - //! for given sliced multilayer and wavevector k - 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 a set of kz projections corresponding to each slice - ISpecularStrategy::coeffs_t Execute(const std::vector<Slice>& slices, - const std::vector<complex_t>& kz) const; - -private: - std::vector<MatrixRTCoefficients_v3> computeTR(const std::vector<Slice>& slices, - const std::vector<complex_t>& kzs) const; - - virtual std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> - computeBackwardsSubmatrices(const MatrixRTCoefficients_v3& coeff_i, - const MatrixRTCoefficients_v3& coeff_i1, double sigma) const = 0; - - void calculateUpwards(std::vector<MatrixRTCoefficients_v3>& coeff, - const std::vector<Slice>& slices) const; -}; - -#endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWSTRATEGY_H diff --git a/Sample/Specular/SpecularMagneticOldStrategy.h b/Sample/Specular/SpecularMagneticOldStrategy.h deleted file mode 100644 index 88e6b17d87a4fe36201f586c7049bb7fbd595f39..0000000000000000000000000000000000000000 --- a/Sample/Specular/SpecularMagneticOldStrategy.h +++ /dev/null @@ -1,39 +0,0 @@ -// ************************************************************************************************ -// -// BornAgain: simulate and fit scattering at grazing incidence -// -//! @file Sample/Specular/SpecularMagneticOldStrategy.h -//! @brief Defines class SpecularMagneticOldStrategy. -//! -//! @homepage http://www.bornagainproject.org -//! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 -//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) -// -// ************************************************************************************************ - -#ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICOLDSTRATEGY_H -#define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICOLDSTRATEGY_H - -#include "Sample/RT/MatrixRTCoefficients.h" -#include "Sample/Specular/ISpecularStrategy.h" -#include <memory> -#include <vector> - -class Slice; - -//! Implements the matrix formalism for the calculation of wave amplitudes of -//! the coherent wave solution in a multilayer with magnetization. -//! @ingroup algorithms_internal - -class SpecularMagneticOldStrategy : public ISpecularStrategy { -public: - //! Computes refraction angle reflection/transmission coefficients - //! for given sliced multilayer and wavevector k - coeffs_t Execute(const std::vector<Slice>& slices, const kvector_t& k) const; - - coeffs_t Execute(const std::vector<Slice>& slices, const std::vector<complex_t>& kz) const; - -}; // class SpecularMagneticOldStrategy - -#endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICOLDSTRATEGY_H diff --git a/Sample/Specular/SpecularMagneticStrategy.cpp b/Sample/Specular/SpecularMagneticStrategy.cpp index b46fca7567fd7a7700ecc2e9945649524eb651f3..e940ff0093f780eea1efa006bd760c139848e5ce 100644 --- a/Sample/Specular/SpecularMagneticStrategy.cpp +++ b/Sample/Specular/SpecularMagneticStrategy.cpp @@ -7,7 +7,7 @@ //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @copyright Forschungszentrum Jülich GmbH 2020 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ @@ -15,42 +15,44 @@ #include "Sample/Specular/SpecularMagneticStrategy.h" #include "Base/Const/PhysicalConstants.h" #include "Sample/Slice/KzComputation.h" +#include "Sample/Slice/LayerRoughness.h" #include "Sample/Slice/Slice.h" namespace { -kvector_t magneticImpact(kvector_t B_field); +double magneticSLD(kvector_t B_field); Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag); Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs); -complex_t GetImExponential(complex_t exponent); // The factor 1e-18 is here to have unit: 1/T*nm^-2 constexpr double magnetic_prefactor = PhysConsts::m_n * PhysConsts::g_factor_n * PhysConsts::mu_N - / PhysConsts::h_bar / PhysConsts::h_bar * 1e-18; + / PhysConsts::h_bar / PhysConsts::h_bar / 4. / M_PI * 1e-18; +const auto eps = std::numeric_limits<double>::epsilon() * 10.; +const LayerRoughness* GetBottomRoughness(const std::vector<Slice>& slices, + const size_t slice_index); } // namespace ISpecularStrategy::coeffs_t SpecularMagneticStrategy::Execute(const std::vector<Slice>& slices, - const kvector_t& k) const { + const kvector_t& k) const { return Execute(slices, KzComputation::computeReducedKz(slices, k)); } ISpecularStrategy::coeffs_t SpecularMagneticStrategy::Execute(const std::vector<Slice>& slices, - const std::vector<complex_t>& kz) const { + const std::vector<complex_t>& kz) const { if (slices.size() != kz.size()) throw std::runtime_error("Number of slices does not match the size of the kz-vector"); ISpecularStrategy::coeffs_t result; for (auto& coeff : computeTR(slices, kz)) - result.push_back(std::make_unique<MatrixRTCoefficients_v2>(coeff)); + result.push_back(std::make_unique<MatrixRTCoefficients>(coeff)); return result; } -std::vector<MatrixRTCoefficients_v2> +std::vector<MatrixRTCoefficients> SpecularMagneticStrategy::computeTR(const std::vector<Slice>& slices, - const std::vector<complex_t>& kzs) { - if (kzs[0] == 0.) - throw std::runtime_error("Edge case k_z = 0 not implemented"); + const std::vector<complex_t>& kzs) const { + const size_t N = slices.size(); if (slices.size() != kzs.size()) throw std::runtime_error( @@ -58,206 +60,113 @@ SpecularMagneticStrategy::computeTR(const std::vector<Slice>& slices, if (slices.empty()) return {}; - std::vector<MatrixRTCoefficients_v2> result; - result.reserve(slices.size()); + std::vector<MatrixRTCoefficients> result; + result.reserve(N); - const double kz_sign = kzs.front().real() > 0.0 ? 1.0 : -1.0; // save sign to restore it later - const kvector_t b_0 = magneticImpact(slices.front().bField()); - result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0}); + const double kz_sign = kzs.front().real() >= 0.0 ? 1.0 : -1.0; // save sign to restore it later + + auto B_0 = slices.front().bField(); + result.emplace_back(kz_sign, eigenvalues(kzs.front(), 0.0), kvector_t{0.0, 0.0, 0.0}, 0.0); for (size_t i = 1, size = slices.size(); i < size; ++i) { - kvector_t b = magneticImpact(slices[i].bField()) - b_0; - result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], b.mag())), b); + auto B = slices[i].bField() - B_0; + auto magnetic_SLD = magneticSLD(B); + result.emplace_back(kz_sign, checkForUnderflow(eigenvalues(kzs[i], magnetic_SLD)), + B.mag() > eps ? B / B.mag() : kvector_t{0.0, 0.0, 0.0}, magnetic_SLD); } - if (result.front().m_lambda == Eigen::Vector2cd::Zero()) { - std::for_each(result.begin(), result.end(), [](auto& coeff) { setNoTransmission(coeff); }); + if (N == 1) { + result[0].m_T = Eigen::Matrix2cd::Identity(); + result[0].m_R = Eigen::Matrix2cd::Zero(); return result; - } - - std::for_each(result.begin(), result.end(), [](auto& coeff) { calculateTR(coeff); }); - nullifyBottomReflection(result.back()); - propagateBackwardsForwards(result, slices); - - return result; -} -void SpecularMagneticStrategy::calculateTR(MatrixRTCoefficients_v2& coeff) { - const double b = coeff.m_b.mag(); - if (b == 0.0) { - calculateZeroFieldTR(coeff); - return; + } else if (kzs[0] == 0.) { + result[0].m_T = Eigen::Matrix2cd::Identity(); + result[0].m_R = -Eigen::Matrix2cd::Identity(); + for (size_t i = 1; i < N; ++i) { + result[i].m_T.setZero(); + result[i].m_R.setZero(); + } + return result; } - const double bpbz = b + coeff.m_b.z(); - const double bmbz = b - coeff.m_b.z(); - const complex_t bxmby = coeff.m_b.x() - I * coeff.m_b.y(); - const complex_t bxpby = coeff.m_b.x() + I * coeff.m_b.y(); - const complex_t l_1 = coeff.m_lambda(0); - const complex_t l_2 = coeff.m_lambda(1); - - auto& T1 = coeff.T1; - T1 << bmbz, -bxmby, -bmbz * l_1, bxmby * l_1, -bxpby, bpbz, bxpby * l_1, -bpbz * l_1, - -bmbz / l_1, bxmby / l_1, bmbz, -bxmby, bxpby / l_1, -bpbz / l_1, -bxpby, bpbz; - T1 /= 4.0 * b; - - auto& R1 = coeff.R1; - 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), - -T1(2, 0), -T1(2, 1), T1(2, 2), T1(2, 3), -T1(3, 0), -T1(3, 1), T1(3, 2), T1(3, 3); - - auto& T2 = coeff.T2; - T2 << bpbz, bxmby, -bpbz * l_2, -bxmby * l_2, bxpby, bmbz, -bxpby * l_2, -bmbz * l_2, - -bpbz / l_2, -bxmby / l_2, bpbz, bxmby, -bxpby / l_2, -bmbz / l_2, bxpby, bmbz; - T2 /= 4.0 * b; - - auto& R2 = coeff.R2; - 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), - -T2(2, 0), -T2(2, 1), T2(2, 2), T2(2, 3), -T2(3, 0), -T2(3, 1), T2(3, 2), T2(3, 3); -} - -void SpecularMagneticStrategy::calculateZeroFieldTR(MatrixRTCoefficients_v2& coeff) { - coeff.T1 = Eigen::Matrix4cd::Zero(); - coeff.R1 = Eigen::Matrix4cd::Zero(); - coeff.T2 = Eigen::Matrix4cd::Zero(); - coeff.R2 = Eigen::Matrix4cd::Zero(); - - // lambda_1 == lambda_2, no difference which one to use - const complex_t eigen_value = coeff.m_lambda(0); - - Eigen::Matrix3cd Tblock; - Tblock << 0.5, 0.0, -0.5 * eigen_value, 0.0, 0.0, 0.0, -0.5 / eigen_value, 0.0, 0.5; - - Eigen::Matrix3cd Rblock; - Rblock << 0.5, 0.0, 0.5 * eigen_value, 0.0, 0.0, 0.0, 0.5 / eigen_value, 0.0, 0.5; - - coeff.T1.block<3, 3>(1, 1) = Tblock; - coeff.R1.block<3, 3>(1, 1) = Rblock; - coeff.T2.block<3, 3>(0, 0) = Tblock; - coeff.R2.block<3, 3>(0, 0) = Rblock; -} + calculateUpwards(result, slices); -void SpecularMagneticStrategy::setNoTransmission(MatrixRTCoefficients_v2& coeff) { - coeff.m_w_plus = Eigen::Vector4cd::Zero(); - coeff.m_w_min = Eigen::Vector4cd::Zero(); - coeff.T1 = Eigen::Matrix4cd::Identity() / 4.0; - coeff.R1 = coeff.T1; - coeff.T2 = coeff.T1; - coeff.R2 = coeff.T1; -} - -void SpecularMagneticStrategy::nullifyBottomReflection(MatrixRTCoefficients_v2& coeff) { - const complex_t l_1 = coeff.m_lambda(0); - const complex_t l_2 = coeff.m_lambda(1); - const double b_mag = coeff.m_b.mag(); - const kvector_t& b = coeff.m_b; - - if (b_mag == 0.0) { - // both eigenvalues are the same, no difference which one to take - coeff.m_w_plus << -l_1, 0.0, 1.0, 0.0; - coeff.m_w_min << 0.0, -l_1, 0.0, 1.0; - return; - } - - // First basis vector that has no upward going wave amplitude - coeff.m_w_min(0) = (b.x() - I * b.y()) * (l_1 - l_2) / 2.0 / b_mag; - coeff.m_w_min(1) = b.z() * (l_2 - l_1) / 2.0 / b_mag - (l_1 + l_2) / 2.0; - coeff.m_w_min(2) = 0.0; - coeff.m_w_min(3) = 1.0; - - // Second basis vector that has no upward going wave amplitude - coeff.m_w_plus(0) = -(l_1 + l_2) / 2.0 - b.z() / (l_1 + l_2); - coeff.m_w_plus(1) = (b.x() + I * b.y()) * (l_1 - l_2) / 2.0 / b_mag; - coeff.m_w_plus(2) = 1.0; - coeff.m_w_plus(3) = 0.0; + return result; } -void SpecularMagneticStrategy::propagateBackwardsForwards( - std::vector<MatrixRTCoefficients_v2>& coeff, const std::vector<Slice>& slices) { - const int size = static_cast<int>(coeff.size()); - std::vector<Eigen::Matrix2cd> SMatrices(coeff.size()); - std::vector<complex_t> Normalization(coeff.size()); - - for (int index = size - 2; index >= 0; --index) { - const size_t i = static_cast<size_t>(index); - const double t = slices[i].thickness(); - const auto kz = coeff[i].getKz(); - const Eigen::Matrix4cd l = coeff[i].R1 * GetImExponential(kz(0) * t) - + coeff[i].T1 * GetImExponential(-kz(0) * t) - + coeff[i].R2 * GetImExponential(kz(1) * t) - + coeff[i].T2 * GetImExponential(-kz(1) * t); - coeff[i].m_w_plus = l * coeff[i + 1].m_w_plus; - coeff[i].m_w_min = l * coeff[i + 1].m_w_min; - - // rotate and normalize polarization - const auto Snorm = findNormalizationCoefficients(coeff[i]); - auto S = Snorm.first; - auto norm = Snorm.second; - +void SpecularMagneticStrategy::calculateUpwards(std::vector<MatrixRTCoefficients>& coeff, + const std::vector<Slice>& slices) const { + const auto N = slices.size(); + std::vector<Eigen::Matrix2cd> SMatrices(N - 1); + std::vector<complex_t> Normalization(N - 1); + + // bottom boundary condition + coeff.back().m_T = Eigen::Matrix2cd::Identity(); + coeff.back().m_R = Eigen::Matrix2cd::Zero(); + + for (int i = N - 2; i >= 0; --i) { + double sigma = 0.; + if (const auto roughness = GetBottomRoughness(slices, i)) + sigma = roughness->getSigma(); + + // compute the 2x2 submatrices in the write-up denoted as P+, P- and delta + const auto mpmm = computeBackwardsSubmatrices(coeff[i], coeff[i + 1], sigma); + const Eigen::Matrix2cd mp = mpmm.first; + const Eigen::Matrix2cd mm = mpmm.second; + + const Eigen::Matrix2cd delta = coeff[i].computeDeltaMatrix(slices[i].thickness()); + + // compute the rotation matrix + Eigen::Matrix2cd S, Si; + Si = mp + mm * coeff[i + 1].m_R; + S << Si(1, 1), -Si(0, 1), -Si(1, 0), Si(0, 0); + const complex_t norm = S(0, 0) * S(1, 1) - S(0, 1) * S(1, 0); + S = S * delta; + + // store the rotation matrix and normalization constant in order to rotate + // the coefficients for all lower slices at the end of the computation SMatrices[i] = S; Normalization[i] = norm; - const complex_t a_plus = S(0, 0) / norm; - const complex_t b_plus = S(1, 0) / norm; - const complex_t a_min = S(0, 1) / norm; - const complex_t b_min = S(1, 1) / norm; - - const Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min; - const Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min; + // compute the reflection matrix and + // rotate the polarization such that we have pure incoming states (T = I) + S /= norm; - coeff[i].m_w_plus = std::move(w_plus); - coeff[i].m_w_min = std::move(w_min); + // T is always equal to the identity at this point, no need to store + coeff[i].m_R = delta * (mm + mp * coeff[i + 1].m_R) * S; } + // now correct all amplitudes in forward direction by dividing with the remaining + // normalization constants. In addition rotate the polarization by the amount + // that was rotated above the current interface + // if the normalization overflows, all amplitudes below that point are set to zero complex_t dumpingFactor = 1; Eigen::Matrix2cd S = Eigen::Matrix2cd::Identity(); - for (size_t i = 1; i < coeff.size(); ++i) { + for (size_t i = 1; i < N; ++i) { dumpingFactor = dumpingFactor * Normalization[i - 1]; S = SMatrices[i - 1] * S; if (std::isinf(std::norm(dumpingFactor))) { - // not entirely sure, whether this is the correct edge case - std::for_each(coeff.begin() + i, coeff.end(), - [](auto& coeff) { setNoTransmission(coeff); }); + std::for_each(coeff.begin() + i, coeff.end(), [](auto& coeff) { + coeff.m_T = Eigen::Matrix2cd::Zero(); + coeff.m_R = Eigen::Matrix2cd::Zero(); + }); break; } - const complex_t a_plus = S(0, 0) / dumpingFactor; - const complex_t b_plus = S(1, 0) / dumpingFactor; - const complex_t a_min = S(0, 1) / dumpingFactor; - const complex_t b_min = S(1, 1) / dumpingFactor; - - Eigen::Vector4cd w_plus = a_plus * coeff[i].m_w_plus + b_plus * coeff[i].m_w_min; - Eigen::Vector4cd w_min = a_min * coeff[i].m_w_plus + b_min * coeff[i].m_w_min; - - coeff[i].m_w_plus = std::move(w_plus); - coeff[i].m_w_min = std::move(w_min); + coeff[i].m_T = S / dumpingFactor; // T * S omitted, since T is always I + coeff[i].m_R *= S / dumpingFactor; } } -std::pair<Eigen::Matrix2cd, complex_t> -SpecularMagneticStrategy::findNormalizationCoefficients(const MatrixRTCoefficients_v2& coeff) { - const Eigen::Vector2cd Ta = coeff.T1plus() + coeff.T2plus(); - const Eigen::Vector2cd Tb = coeff.T1min() + coeff.T2min(); - - Eigen::Matrix2cd S; - S << Ta(0), Tb(0), Ta(1), Tb(1); - - Eigen::Matrix2cd SInverse; - SInverse << S(1, 1), -S(0, 1), -S(1, 0), S(0, 0); - const complex_t d1 = S(1, 1) - S(0, 1); - const complex_t d2 = S(1, 0) - S(0, 0); - const complex_t denominator = S(0, 0) * d1 - d2 * S(0, 1); - - return {SInverse, denominator}; -} - namespace { -kvector_t magneticImpact(kvector_t B_field) { - return -magnetic_prefactor * B_field; +double magneticSLD(kvector_t B_field) { + return magnetic_prefactor * B_field.mag(); } -Eigen::Vector2cd eigenvalues(complex_t kz, double b_mag) { +Eigen::Vector2cd eigenvalues(complex_t kz, double magnetic_SLD) { const complex_t a = kz * kz; - return {I * std::sqrt(a + b_mag), I * std::sqrt(a - b_mag)}; + return {std::sqrt(a - 4. * M_PI * magnetic_SLD), std::sqrt(a + 4. * M_PI * magnetic_SLD)}; } Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs) { @@ -265,9 +174,10 @@ Eigen::Vector2cd checkForUnderflow(const Eigen::Vector2cd& eigenvs) { return {lambda(eigenvs(0)), lambda(eigenvs(1))}; } -complex_t GetImExponential(complex_t exponent) { - if (exponent.imag() > -std::log(std::numeric_limits<double>::min())) - return 0.0; - return std::exp(I * exponent); +const LayerRoughness* GetBottomRoughness(const std::vector<Slice>& slices, + const size_t slice_index) { + if (slice_index + 1 < slices.size()) + return slices[slice_index + 1].topRoughness(); + return nullptr; } } // namespace diff --git a/Sample/Specular/SpecularMagneticStrategy.h b/Sample/Specular/SpecularMagneticStrategy.h index 31a5c12d73652606c60f857d247a813494b713b1..4906c817a347788beb1d0d649d3f152bf81c8877 100644 --- a/Sample/Specular/SpecularMagneticStrategy.h +++ b/Sample/Specular/SpecularMagneticStrategy.h @@ -7,7 +7,7 @@ //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) -//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @copyright Forschungszentrum Jülich GmbH 2020 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) // // ************************************************************************************************ @@ -15,25 +15,33 @@ #ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICSTRATEGY_H #define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICSTRATEGY_H -#include "Sample/RT/MatrixRTCoefficients_v2.h" +#include "Sample/RT/MatrixRTCoefficients.h" #include "Sample/Specular/ISpecularStrategy.h" #include <memory> #include <vector> class Slice; -//! Implements the magnetic Fresnel computation without roughness +//! Implements the magnetic Fresnel computation with Nevot-Croce roughness //! -//! Implements the matrix formalism for the calculation of wave amplitudes of -//! the coherent wave solution in a multilayer with magnetization. -//! For a detailed description see internal document "Polarized Specular Reflectometry" +//! Implements the transfer matrix formalism for the calculation of wave +//! amplitudes of the coherent wave solution in a multilayer with magnetization. +//! For a description, see internal +//! document "Polarized Implementation of the Transfer Matrix Method" //! //! @ingroup algorithms_internal class SpecularMagneticStrategy : public ISpecularStrategy { public: + // TODO remove once external test code is not needed anmyore + // for the moment i need them! + using coefficient_type = MatrixRTCoefficients; + using coefficient_pointer_type = std::unique_ptr<const coefficient_type>; + using coeffs_t = std::vector<coefficient_pointer_type>; + //! Computes refraction angle reflection/transmission coefficients //! for given sliced multilayer and wavevector k - ISpecularStrategy::coeffs_t Execute(const std::vector<Slice>& slices, const kvector_t& k) const; + 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 a set of kz projections corresponding to each slice @@ -41,30 +49,15 @@ public: const std::vector<complex_t>& kz) const; private: - static std::vector<MatrixRTCoefficients_v2> computeTR(const std::vector<Slice>& slices, - const std::vector<complex_t>& kzs); - - //! Computes frobenius matrices for multilayer solution - static void calculateTR(MatrixRTCoefficients_v2& coeff); - static void calculateZeroFieldTR(MatrixRTCoefficients_v2& coeff); - - static void setNoTransmission(MatrixRTCoefficients_v2& coeff); - - //! initializes reflectionless bottom boundary condition. - static void nullifyBottomReflection(MatrixRTCoefficients_v2& coeff); + std::vector<MatrixRTCoefficients> computeTR(const std::vector<Slice>& slices, + const std::vector<complex_t>& kzs) const; - //! Propagates boundary conditions from the bottom to the top of the layer stack. - //! Used to compute boundary conditions from the bottom one (with nullified reflection) - //! simultaneously propagates amplitudes forward again - //! Due to the use of temporary objects this is combined into one function now - static void propagateBackwardsForwards(std::vector<MatrixRTCoefficients_v2>& coeff, - const std::vector<Slice>& slices); + virtual std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> + computeBackwardsSubmatrices(const MatrixRTCoefficients& coeff_i, + const MatrixRTCoefficients& coeff_i1, double sigma) const = 0; - //! finds linear coefficients for normalizing transmitted wave to unity. - //! The left column of the returned matrix corresponds to the coefficients for pure spin-up - //! wave, while the right column - to the coefficients for the spin-down one. - static std::pair<Eigen::Matrix2cd, complex_t> - findNormalizationCoefficients(const MatrixRTCoefficients_v2& coeff); + void calculateUpwards(std::vector<MatrixRTCoefficients>& coeff, + const std::vector<Slice>& slices) const; }; #endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICSTRATEGY_H diff --git a/Sample/Specular/SpecularMagneticNewTanhStrategy.cpp b/Sample/Specular/SpecularMagneticTanhStrategy.cpp similarity index 86% rename from Sample/Specular/SpecularMagneticNewTanhStrategy.cpp rename to Sample/Specular/SpecularMagneticTanhStrategy.cpp index 79708afac0ff317c4570834079e18dc2dd7810bc..6ddc26a6b29f2b01335ad9947af7070f1922a750 100644 --- a/Sample/Specular/SpecularMagneticNewTanhStrategy.cpp +++ b/Sample/Specular/SpecularMagneticTanhStrategy.cpp @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/Specular/SpecularMagneticNewTanhStrategy.cpp -//! @brief Implements class SpecularMagneticNewTanhStrategy. +//! @file Sample/Specular/SpecularMagneticTanhStrategy.cpp +//! @brief Implements class SpecularMagneticTanhStrategy. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,7 +12,7 @@ // // ************************************************************************************************ -#include "Sample/Specular/SpecularMagneticNewTanhStrategy.h" +#include "Sample/Specular/SpecularMagneticTanhStrategy.h" #include "Base/Math/Constants.h" #include "Base/Math/Functions.h" @@ -21,7 +21,7 @@ const double pi2_15 = std::pow(M_PI_2, 1.5); } // namespace Eigen::Matrix2cd -SpecularMagneticNewTanhStrategy::computeRoughnessMatrix(const MatrixRTCoefficients_v3& coeff, +SpecularMagneticTanhStrategy::computeRoughnessMatrix(const MatrixRTCoefficients& coeff, double sigma, bool inverse) const { if (sigma < 10 * std::numeric_limits<double>::epsilon()) return Eigen::Matrix2cd{Eigen::Matrix2cd::Identity()}; @@ -60,8 +60,8 @@ SpecularMagneticNewTanhStrategy::computeRoughnessMatrix(const MatrixRTCoefficien } std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> -SpecularMagneticNewTanhStrategy::computeBackwardsSubmatrices( - const MatrixRTCoefficients_v3& coeff_i, const MatrixRTCoefficients_v3& coeff_i1, +SpecularMagneticTanhStrategy::computeBackwardsSubmatrices( + const MatrixRTCoefficients& coeff_i, const MatrixRTCoefficients& coeff_i1, double sigma) const { Eigen::Matrix2cd R{Eigen::Matrix2cd::Identity()}; Eigen::Matrix2cd RInv{Eigen::Matrix2cd::Identity()}; diff --git a/Sample/Specular/SpecularMagneticNewTanhStrategy.h b/Sample/Specular/SpecularMagneticTanhStrategy.h similarity index 62% rename from Sample/Specular/SpecularMagneticNewTanhStrategy.h rename to Sample/Specular/SpecularMagneticTanhStrategy.h index 9bcde6f1ab34f9fe0fa8b925c9e7749947e9ab0c..cb10b10636b46930554656c8183a99b63a70b0c6 100644 --- a/Sample/Specular/SpecularMagneticNewTanhStrategy.h +++ b/Sample/Specular/SpecularMagneticTanhStrategy.h @@ -2,8 +2,8 @@ // // BornAgain: simulate and fit scattering at grazing incidence // -//! @file Sample/Specular/SpecularMagneticNewTanhStrategy.h -//! @brief Defines class SpecularMagneticNewTanhStrategy. +//! @file Sample/Specular/SpecularMagneticTanhStrategy.h +//! @brief Defines class SpecularMagneticTanhStrategy. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -12,10 +12,10 @@ // // ************************************************************************************************ -#ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWTANHSTRATEGY_H -#define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWTANHSTRATEGY_H +#ifndef BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICTANHSTRATEGY_H +#define BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICTANHSTRATEGY_H -#include "Sample/Specular/SpecularMagneticNewStrategy.h" +#include "Sample/Specular/SpecularMagneticStrategy.h" //! Implements the magnetic Fresnel computation with the analytical Tanh roughness //! @@ -25,14 +25,14 @@ //! document "Polarized Implementation of the Transfer Matrix Method" //! //! @ingroup algorithms_internal -class SpecularMagneticNewTanhStrategy : public SpecularMagneticNewStrategy { +class SpecularMagneticTanhStrategy : public SpecularMagneticStrategy { private: virtual std::pair<Eigen::Matrix2cd, Eigen::Matrix2cd> - computeBackwardsSubmatrices(const MatrixRTCoefficients_v3& coeff_i, - const MatrixRTCoefficients_v3& coeff_i1, double sigma) const; + computeBackwardsSubmatrices(const MatrixRTCoefficients& coeff_i, + const MatrixRTCoefficients& coeff_i1, double sigma) const; - Eigen::Matrix2cd computeRoughnessMatrix(const MatrixRTCoefficients_v3& coeff, double sigma, + Eigen::Matrix2cd computeRoughnessMatrix(const MatrixRTCoefficients& coeff, double sigma, bool inverse = false) const; }; -#endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICNEWTANHSTRATEGY_H +#endif // BORNAGAIN_SAMPLE_SPECULAR_SPECULARMAGNETICTANHSTRATEGY_H diff --git a/Sample/Specular/SpecularScalarStrategy.h b/Sample/Specular/SpecularScalarStrategy.h index eda61cef769dcc30b9e9ddcba0bcc2fb47afb789..15d8ae24e7b64f55e31e0fd8fe4f54f987bce2b6 100644 --- a/Sample/Specular/SpecularScalarStrategy.h +++ b/Sample/Specular/SpecularScalarStrategy.h @@ -32,6 +32,12 @@ class Slice; //! @ingroup algorithms_internal class SpecularScalarStrategy : public ISpecularStrategy { public: + // TODO remove once external test code is not needed anmyore + // for the moment i need them! + using coefficient_type = ScalarRTCoefficients; + using coefficient_pointer_type = std::unique_ptr<const coefficient_type>; + using coeffs_t = std::vector<coefficient_pointer_type>; + //! Computes refraction angles and transmission/reflection coefficients //! for given coherent wave propagation in a multilayer. virtual ISpecularStrategy::coeffs_t Execute(const std::vector<Slice>& slices, diff --git a/Sample/Specular/SpecularStrategyBuilder.cpp b/Sample/Specular/SpecularStrategyBuilder.cpp index b79d0decf6fbe99dff11a75683ab566a87a7bca8..767d53588522e50607c84bfdaf1edf59f73a8838 100644 --- a/Sample/Specular/SpecularStrategyBuilder.cpp +++ b/Sample/Specular/SpecularStrategyBuilder.cpp @@ -14,8 +14,8 @@ #include "Sample/Specular/SpecularStrategyBuilder.h" #include "Sample/Multilayer/MultiLayerUtils.h" -#include "Sample/Specular/SpecularMagneticNewNCStrategy.h" -#include "Sample/Specular/SpecularMagneticNewTanhStrategy.h" +#include "Sample/Specular/SpecularMagneticNCStrategy.h" +#include "Sample/Specular/SpecularMagneticTanhStrategy.h" #include "Sample/Specular/SpecularScalarNCStrategy.h" #include "Sample/Specular/SpecularScalarTanhStrategy.h" @@ -26,11 +26,11 @@ std::unique_ptr<ISpecularStrategy> SpecularStrategyBuilder::build(const MultiLay if (magnetic) { if (roughnessModel == RoughnessModel::TANH || roughnessModel == RoughnessModel::DEFAULT) { - return std::make_unique<SpecularMagneticNewTanhStrategy>(); + return std::make_unique<SpecularMagneticTanhStrategy>(); } else if (roughnessModel == RoughnessModel::NEVOT_CROCE) { - return std::make_unique<SpecularMagneticNewNCStrategy>(); + return std::make_unique<SpecularMagneticNCStrategy>(); } else throw std::logic_error("Invalid roughness model"); diff --git a/Tests/GTestWrapper/google_test.h b/Tests/GTestWrapper/google_test.h index 1cdb8e03690b95278d089ec39b7213edee426a82..b48f1d4f6dde7968d008458103086f9ddc07393f 100644 --- a/Tests/GTestWrapper/google_test.h +++ b/Tests/GTestWrapper/google_test.h @@ -38,4 +38,16 @@ EXPECT_NEAR_COMPLEX(v1(0), v2(0), eps); \ EXPECT_NEAR_COMPLEX(v1(1), v2(1), eps); +#define EXPECT_NEAR_MATRIXCOEFF(c1, c2, eps) \ + EXPECT_NEAR_VECTOR2CD(c1->T1plus(), c2->T1plus(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->R1plus(), c2->R1plus(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->T2plus(), c2->T2plus(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->R2plus(), c2->R2plus(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->T1min(), c2->T1min(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->R1min(), c2->R1min(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->T2min(), c2->T2min(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->R2min(), c2->R2min(), eps); \ + EXPECT_NEAR_VECTOR2CD(c1->getKz(), c2->getKz(), eps) + + #endif // BORNAGAIN_TESTS_GTESTWRAPPER_GOOGLE_TEST_H diff --git a/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficientsTest.cpp b/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficientsTest.cpp index bcee4702fe57ffae5e474146f4f1ce71b3806bab..ba2843d41185ff3cc07635d0bf5cefd5a399df90 100644 --- a/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficientsTest.cpp +++ b/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficientsTest.cpp @@ -3,55 +3,55 @@ class MatrixRTCoefficientsTest : public ::testing::Test { protected: - MatrixRTCoefficients mrtcDefault; + MatrixRTCoefficients mrtcDefault{-1., {0., 0.}, kvector_t{0.0, 0.0, 0.0}, 0.}; }; TEST_F(MatrixRTCoefficientsTest, T1plus) { Eigen::Vector2cd vector = mrtcDefault.T1plus(); - EXPECT_EQ(complex_t(0.5, 0.0), vector(0)); + EXPECT_EQ(0.0, vector(0)); EXPECT_EQ(0.0, vector(1)); } TEST_F(MatrixRTCoefficientsTest, T1min) { Eigen::Vector2cd vector = mrtcDefault.T1min(); EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(complex_t(0.5, 0.0), vector(1)); + EXPECT_EQ(complex_t(1.0, 0.0), vector(1)); } TEST_F(MatrixRTCoefficientsTest, T2plus) { Eigen::Vector2cd vector = mrtcDefault.T2plus(); - EXPECT_EQ(complex_t(0.5, 0.0), vector(0)); + EXPECT_EQ(complex_t(1.0, 0.0), vector(0)); EXPECT_EQ(0.0, vector(1)); } TEST_F(MatrixRTCoefficientsTest, T2min) { Eigen::Vector2cd vector = mrtcDefault.T2min(); EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(complex_t(0.5, 0.0), vector(1)); + EXPECT_EQ(0.0, vector(1)); } TEST_F(MatrixRTCoefficientsTest, R1plus) { Eigen::Vector2cd vector = mrtcDefault.R1plus(); - EXPECT_EQ(complex_t(-0.5, 0.0), vector(0)); + EXPECT_EQ(0.0, vector(0)); EXPECT_EQ(0.0, vector(1)); } TEST_F(MatrixRTCoefficientsTest, R1min) { Eigen::Vector2cd vector = mrtcDefault.R1min(); EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(complex_t(-0.5, 0.0), vector(1)); + EXPECT_EQ(complex_t(-1.0, 0.0), vector(1)); } TEST_F(MatrixRTCoefficientsTest, R2plus) { Eigen::Vector2cd vector = mrtcDefault.R2plus(); - EXPECT_EQ(complex_t(-0.5, 0.0), vector(0)); + EXPECT_EQ(complex_t(-1.0, 0.0), vector(0)); EXPECT_EQ(0.0, vector(1)); } TEST_F(MatrixRTCoefficientsTest, R2min) { Eigen::Vector2cd vector = mrtcDefault.R2min(); EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(complex_t(-0.5, 0.0), vector(1)); + EXPECT_EQ(0.0, vector(1)); } TEST_F(MatrixRTCoefficientsTest, getKz) { diff --git a/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficients_v3Test.cpp b/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficients_v3Test.cpp deleted file mode 100644 index e237eb7ba99880cb71b9575364b84710308a0501..0000000000000000000000000000000000000000 --- a/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficients_v3Test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "Sample/RT/MatrixRTCoefficients_v3.h" -#include "Tests/GTestWrapper/google_test.h" - -class MatrixRTCoefficients_v3Test : public ::testing::Test { -protected: - MatrixRTCoefficients_v3 mrtcDefault{-1., {0., 0.}, kvector_t{0.0, 0.0, 0.0}, 0.}; -}; - -TEST_F(MatrixRTCoefficients_v3Test, T1plus) { - Eigen::Vector2cd vector = mrtcDefault.T1plus(); - EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(0.0, vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, T1min) { - Eigen::Vector2cd vector = mrtcDefault.T1min(); - EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(complex_t(1.0, 0.0), vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, T2plus) { - Eigen::Vector2cd vector = mrtcDefault.T2plus(); - EXPECT_EQ(complex_t(1.0, 0.0), vector(0)); - EXPECT_EQ(0.0, vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, T2min) { - Eigen::Vector2cd vector = mrtcDefault.T2min(); - EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(0.0, vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, R1plus) { - Eigen::Vector2cd vector = mrtcDefault.R1plus(); - EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(0.0, vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, R1min) { - Eigen::Vector2cd vector = mrtcDefault.R1min(); - EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(complex_t(-1.0, 0.0), vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, R2plus) { - Eigen::Vector2cd vector = mrtcDefault.R2plus(); - EXPECT_EQ(complex_t(-1.0, 0.0), vector(0)); - EXPECT_EQ(0.0, vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, R2min) { - Eigen::Vector2cd vector = mrtcDefault.R2min(); - EXPECT_EQ(0.0, vector(0)); - EXPECT_EQ(0.0, vector(1)); -} - -TEST_F(MatrixRTCoefficients_v3Test, getKz) { - Eigen::Vector2cd vector = mrtcDefault.getKz(); - EXPECT_EQ(complex_t(0.0, 0.0), vector(0)); - EXPECT_EQ(complex_t(0.0, 0.0), vector(1)); -} diff --git a/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp b/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp index bff76f55318ac388cbeca38d3bfc359b64ee6715..9d57f448becfc1511b5fc9cc14a49a1133a8a1fc 100644 --- a/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp +++ b/Tests/UnitTests/Core/Fresnel/SpecularMagneticTest.cpp @@ -1,30 +1,31 @@ #include "Base/Const/Units.h" +#include "Core/Legacy/SpecularMagneticStrategy_v2.h" #include "Sample/Material/MaterialFactoryFuncs.h" #include "Sample/Multilayer/Layer.h" #include "Sample/Multilayer/MultiLayer.h" #include "Sample/Processed/ProcessedSample.h" #include "Sample/RT/SimulationOptions.h" #include "Sample/Slice/KzComputation.h" -#include "Sample/Specular/SpecularMagneticNewTanhStrategy.h" -#include "Sample/Specular/SpecularMagneticStrategy.h" +#include "Sample/Specular/SpecularMagneticTanhStrategy.h" #include "Sample/Specular/SpecularScalarTanhStrategy.h" #include "Tests/GTestWrapper/google_test.h" #include <utility> -constexpr double eps = 1e-10; class SpecularMagneticTest : public ::testing::Test { protected: - std::unique_ptr<ProcessedSample> sample_zerofield(); + auto static constexpr eps = 1.e-10; + + std::unique_ptr<ProcessedSample> sample_zerofield(bool slab); std::unique_ptr<ProcessedSample> sample_degenerate(); template <typename Strategy> void test_degenerate(); template <typename Strategy> void testZeroField(const kvector_t& k, const ProcessedSample& sample); - template <typename Strategy> void testcase_zerofield(std::vector<double>&& angles); + template <typename Strategy> void testcase_zerofield(std::vector<double>&& angles, bool slab=false); }; -template <> void SpecularMagneticTest::test_degenerate<SpecularMagneticNewTanhStrategy>() { +template <> void SpecularMagneticTest::test_degenerate<SpecularMagneticTanhStrategy>() { kvector_t v; Eigen::Vector2cd T1p{0.0, 0.0}; @@ -37,7 +38,7 @@ template <> void SpecularMagneticTest::test_degenerate<SpecularMagneticNewTanhSt Eigen::Vector2cd R2m{0.0, 0.0}; auto sample = sample_degenerate(); - auto result = std::make_unique<SpecularMagneticNewTanhStrategy>()->Execute(sample->slices(), v); + auto result = std::make_unique<SpecularMagneticTanhStrategy>()->Execute(sample->slices(), v); for (auto& coeff : result) { EXPECT_NEAR_VECTOR2CD(coeff->T1plus(), T1p, eps); EXPECT_NEAR_VECTOR2CD(coeff->T2plus(), T2p, eps); @@ -85,16 +86,23 @@ std::unique_ptr<ProcessedSample> SpecularMagneticTest::sample_degenerate() { return std::make_unique<ProcessedSample>(mLayer, SimulationOptions()); } -TEST_F(SpecularMagneticTest, degenerate_new) { - test_degenerate<SpecularMagneticNewTanhStrategy>(); +TEST_F(SpecularMagneticTest, degenerate_) { + test_degenerate<SpecularMagneticTanhStrategy>(); } -std::unique_ptr<ProcessedSample> SpecularMagneticTest::sample_zerofield() { +std::unique_ptr<ProcessedSample> SpecularMagneticTest::sample_zerofield(bool slab) { MultiLayer multi_layer_scalar; Material substr_material_scalar = HomogeneousMaterial("Substrate", 7e-6, 2e-8); Layer vacuum_layer(HomogeneousMaterial("Vacuum", 0.0, 0.0)); Layer substr_layer_scalar(substr_material_scalar); multi_layer_scalar.addLayer(vacuum_layer); + + if(slab) { + Material layer_material = HomogeneousMaterial("Layer", 3e-6, 1e-8); + Layer layer(layer_material, 10. * Units::nm); + multi_layer_scalar.addLayer(layer); + } + multi_layer_scalar.addLayer(substr_layer_scalar); SimulationOptions options; @@ -104,18 +112,43 @@ std::unique_ptr<ProcessedSample> SpecularMagneticTest::sample_zerofield() { } template <typename Strategy> -void SpecularMagneticTest::testcase_zerofield(std::vector<double>&& angles) { +void SpecularMagneticTest::testcase_zerofield(std::vector<double>&& angles, bool slab) { for (auto& angle : angles) { - auto sample = sample_zerofield(); + auto sample = sample_zerofield(slab); kvector_t k = vecOfLambdaAlphaPhi(1.0, angle * Units::deg, 0.0); testZeroField<Strategy>(k, *sample); } } -TEST_F(SpecularMagneticTest, zerofield) { - testcase_zerofield<SpecularMagneticStrategy>({-0.1, -2.0, -10.0}); +TEST_F(SpecularMagneticTest, zerofield_v2_negative_k) { + testcase_zerofield<SpecularMagneticStrategy_v2>({-0.1, -2.0, -10.0}); +} + +TEST_F(SpecularMagneticTest, zerofield_v2_positive_k) { + testcase_zerofield<SpecularMagneticStrategy_v2>({0.1, 2.0, 10.0}); +} + +TEST_F(SpecularMagneticTest, zerofield2_v2_negative_k) { + testcase_zerofield<SpecularMagneticStrategy_v2>({-0.1, -2.0, -10.0}, true); +} + +TEST_F(SpecularMagneticTest, zerofield2_v2_positive_k) { + testcase_zerofield<SpecularMagneticStrategy_v2>({0.1, 2.0, 10.0}, true); +} + + +TEST_F(SpecularMagneticTest, zerofield_positive_k) { + testcase_zerofield<SpecularMagneticTanhStrategy>({0.0, 1.e-9, 1.e-5, 0.1, 2.0, 10.0}); +} + +TEST_F(SpecularMagneticTest, zerofield_negative_k) { + testcase_zerofield<SpecularMagneticTanhStrategy>({-0.0, -1.e-9, -1.e-5, -0.1, -2.0, -10.0}); +} + +TEST_F(SpecularMagneticTest, zerofield2_positive_k) { + testcase_zerofield<SpecularMagneticTanhStrategy>({0.0, 1.e-9, 1.e-5, 0.1, 2.0, 10.0}, true); } -TEST_F(SpecularMagneticTest, zerofield_new) { - testcase_zerofield<SpecularMagneticNewTanhStrategy>({-0.0, -1.e-9, -1.e-5, -0.1, -2.0, -10.0}); +TEST_F(SpecularMagneticTest, zerofield2_negative_k) { + testcase_zerofield<SpecularMagneticTanhStrategy>({-0.0, -1.e-9, -1.e-5, -0.1, -2.0, -10.0}, true); } diff --git a/Tests/UnitTests/Core/Legacy/MatrixRTCoefficients_v1Test.cpp b/Tests/UnitTests/Core/Legacy/MatrixRTCoefficients_v1Test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b8d11b56eb535adb469acfc3dffb5258da8023d --- /dev/null +++ b/Tests/UnitTests/Core/Legacy/MatrixRTCoefficients_v1Test.cpp @@ -0,0 +1,61 @@ +#include "Core/Legacy/MatrixRTCoefficients_v1.h" +#include "Tests/GTestWrapper/google_test.h" + +class MatrixRTCoefficients_v1Test : public ::testing::Test { +protected: + MatrixRTCoefficients_v1 mrtcDefault; +}; + +TEST_F(MatrixRTCoefficients_v1Test, T1plus) { + Eigen::Vector2cd vector = mrtcDefault.T1plus(); + EXPECT_EQ(complex_t(0.5, 0.0), vector(0)); + EXPECT_EQ(0.0, vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, T1min) { + Eigen::Vector2cd vector = mrtcDefault.T1min(); + EXPECT_EQ(0.0, vector(0)); + EXPECT_EQ(complex_t(0.5, 0.0), vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, T2plus) { + Eigen::Vector2cd vector = mrtcDefault.T2plus(); + EXPECT_EQ(complex_t(0.5, 0.0), vector(0)); + EXPECT_EQ(0.0, vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, T2min) { + Eigen::Vector2cd vector = mrtcDefault.T2min(); + EXPECT_EQ(0.0, vector(0)); + EXPECT_EQ(complex_t(0.5, 0.0), vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, R1plus) { + Eigen::Vector2cd vector = mrtcDefault.R1plus(); + EXPECT_EQ(complex_t(-0.5, 0.0), vector(0)); + EXPECT_EQ(0.0, vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, R1min) { + Eigen::Vector2cd vector = mrtcDefault.R1min(); + EXPECT_EQ(0.0, vector(0)); + EXPECT_EQ(complex_t(-0.5, 0.0), vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, R2plus) { + Eigen::Vector2cd vector = mrtcDefault.R2plus(); + EXPECT_EQ(complex_t(-0.5, 0.0), vector(0)); + EXPECT_EQ(0.0, vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, R2min) { + Eigen::Vector2cd vector = mrtcDefault.R2min(); + EXPECT_EQ(0.0, vector(0)); + EXPECT_EQ(complex_t(-0.5, 0.0), vector(1)); +} + +TEST_F(MatrixRTCoefficients_v1Test, getKz) { + Eigen::Vector2cd vector = mrtcDefault.getKz(); + EXPECT_EQ(complex_t(0.0, 0.0), vector(0)); + EXPECT_EQ(complex_t(0.0, 0.0), vector(1)); +} diff --git a/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficients_v2Test.cpp b/Tests/UnitTests/Core/Legacy/MatrixRTCoefficients_v2Test.cpp similarity index 97% rename from Tests/UnitTests/Core/Fresnel/MatrixRTCoefficients_v2Test.cpp rename to Tests/UnitTests/Core/Legacy/MatrixRTCoefficients_v2Test.cpp index 0fa5397e86bfe38e71e0354e79db25bd31f8ba97..6934736917de848b4e8d7f8eb33e05671035a704 100644 --- a/Tests/UnitTests/Core/Fresnel/MatrixRTCoefficients_v2Test.cpp +++ b/Tests/UnitTests/Core/Legacy/MatrixRTCoefficients_v2Test.cpp @@ -1,4 +1,4 @@ -#include "Sample/RT/MatrixRTCoefficients_v2.h" +#include "Core/Legacy/MatrixRTCoefficients_v2.h" #include "Tests/GTestWrapper/google_test.h" class MatrixRTCoefficients_v2Test : public ::testing::Test { diff --git a/Tests/UnitTests/Core/Legacy/SpecularMagneticConsistencyTest.cpp b/Tests/UnitTests/Core/Legacy/SpecularMagneticConsistencyTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b974632db4aada7df0498462a9502d991eb19e4 --- /dev/null +++ b/Tests/UnitTests/Core/Legacy/SpecularMagneticConsistencyTest.cpp @@ -0,0 +1,72 @@ +#include "Base/Const/Units.h" +#include "Core/Legacy/SpecularMagneticStrategy_v2.h" +#include "Sample/Material/MaterialFactoryFuncs.h" +#include "Sample/Multilayer/Layer.h" +#include "Sample/Multilayer/MultiLayer.h" +#include "Sample/Processed/ProcessedSample.h" +#include "Sample/RT/SimulationOptions.h" +#include "Sample/Slice/KzComputation.h" +#include "Sample/Specular/SpecularMagneticTanhStrategy.h" +#include "Tests/GTestWrapper/google_test.h" + +class SpecularMagneticConsistencyTest : public ::testing::Test +{ +protected: + auto static constexpr eps = 1.e-10; + + std::unique_ptr<ProcessedSample> sample_1(); + + template <typename Strategy1, typename Strategy2> + void testcase(const std::vector<Slice>& slices, double k); +}; + +std::unique_ptr<ProcessedSample> SpecularMagneticConsistencyTest::sample_1() +{ + MultiLayer multi_layer_scalar; + Material substr_material_scalar = HomogeneousMaterial("Substrate", 7e-6, 2e-8); + Material layer_material = HomogeneousMaterial("Layer", 3e-6, 1e-8, kvector_t{1.e7, 0, 1.e7}); + + Layer vacuum_layer(HomogeneousMaterial("Vacuum", 0.0, 0.0)); + Layer substr_layer_scalar(substr_material_scalar); + Layer layer(layer_material, 10. * Units::nm); + + multi_layer_scalar.addLayer(vacuum_layer); + multi_layer_scalar.addLayer(layer); + multi_layer_scalar.addLayer(substr_layer_scalar); + + SimulationOptions options; + auto sample_scalar = std::make_unique<ProcessedSample>(multi_layer_scalar, options); + + return sample_scalar; +} + +template <typename Strategy1, typename Strategy2> +void SpecularMagneticConsistencyTest::testcase(const std::vector<Slice>& slices, double k) +{ + + const auto kz = kvector_t{0., 0., k}; + const auto coeffs1 = std::make_unique<Strategy1>()->Execute( + slices, KzComputation::computeKzFromRefIndices(slices, kz)); + const auto coeffs2 = std::make_unique<Strategy2>()->Execute( + slices, KzComputation::computeKzFromRefIndices(slices, kz)); + + for (size_t i = 0; i < coeffs1.size(); ++i) { + EXPECT_NEAR_MATRIXCOEFF(coeffs1[i], coeffs2[i], eps); + } +} + +TEST_F(SpecularMagneticConsistencyTest, NewOld) +{ + using Strategy1 = SpecularMagneticTanhStrategy; + using Strategy2 = SpecularMagneticStrategy_v2; + + const auto sample = sample_1(); + const auto slices = sample->slices(); + + const std::vector<double> kzs = {1.e-9, 1.e-5, 0.1, 2.0, 10.0}; + + for (const auto& k : kzs) { + testcase<Strategy1, Strategy2>(slices, k); + testcase<Strategy1, Strategy2>(slices, -k); + } +} diff --git a/Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp b/Tests/UnitTests/Core/Legacy/SpecularMagnetic_v1Test.cpp similarity index 87% rename from Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp rename to Tests/UnitTests/Core/Legacy/SpecularMagnetic_v1Test.cpp index bbcd0cd712bf2f42555d1a3f4c17cbe750a2e0e0..adc1ff579bcb32fb7a5268b9ee918e1e4bba7c3d 100644 --- a/Tests/UnitTests/Core/Fresnel/SpecularMagneticOldTest.cpp +++ b/Tests/UnitTests/Core/Legacy/SpecularMagnetic_v1Test.cpp @@ -4,13 +4,13 @@ #include "Sample/Multilayer/MultiLayer.h" #include "Sample/Processed/ProcessedSample.h" #include "Sample/RT/SimulationOptions.h" -#include "Sample/Specular/SpecularMagneticOldStrategy.h" +#include "Core/Legacy/SpecularMagneticStrategy_v1.h" #include "Sample/Specular/SpecularScalarTanhStrategy.h" #include "Tests/GTestWrapper/google_test.h" -class SpecularMagneticOldTest : public ::testing::Test {}; +class SpecularMagnetic_v1Test : public ::testing::Test {}; -TEST_F(SpecularMagneticOldTest, initial) { +TEST_F(SpecularMagnetic_v1Test, initial) { MultiLayer mLayer; kvector_t v; @@ -22,10 +22,10 @@ TEST_F(SpecularMagneticOldTest, initial) { mLayer.addLayer(layer0); SimulationOptions options; ProcessedSample sample(mLayer, options); - std::make_unique<SpecularMagneticOldStrategy>()->Execute(sample.slices(), v); + std::make_unique<SpecularMagneticStrategy_v1>()->Execute(sample.slices(), v); } -TEST_F(SpecularMagneticOldTest, zerofield) { +TEST_F(SpecularMagnetic_v1Test, zerofield) { double eps = 1e-10; kvector_t substr_field(0.0, 0.0, 0.0); @@ -61,9 +61,9 @@ TEST_F(SpecularMagneticOldTest, zerofield) { Eigen::Vector2cd RMS = RTScalar.R1min() + RTScalar.R2min(); auto coeffs_zerofield = - std::make_unique<SpecularMagneticOldStrategy>()->Execute(sample_zerofield.slices(), k1); - MatrixRTCoefficients RTMatrix = - *dynamic_cast<const MatrixRTCoefficients*>(coeffs_zerofield[1].get()); + std::make_unique<SpecularMagneticStrategy_v1>()->Execute(sample_zerofield.slices(), k1); + MatrixRTCoefficients_v1 RTMatrix = + *dynamic_cast<const MatrixRTCoefficients_v1*>(coeffs_zerofield[1].get()); Eigen::Vector2cd TPM = RTMatrix.T1plus() + RTMatrix.T2plus(); Eigen::Vector2cd RPM = RTMatrix.R1plus() + RTMatrix.R2plus(); Eigen::Vector2cd TMM = RTMatrix.T1min() + RTMatrix.T2min(); @@ -88,8 +88,8 @@ TEST_F(SpecularMagneticOldTest, zerofield) { RMS = RTScalar.R1min() + RTScalar.R2min(); coeffs_zerofield = - std::make_unique<SpecularMagneticOldStrategy>()->Execute(sample_zerofield.slices(), k2); - RTMatrix = *dynamic_cast<const MatrixRTCoefficients*>(coeffs_zerofield[1].get()); + std::make_unique<SpecularMagneticStrategy_v1>()->Execute(sample_zerofield.slices(), k2); + RTMatrix = *dynamic_cast<const MatrixRTCoefficients_v1*>(coeffs_zerofield[1].get()); TPM = RTMatrix.T1plus() + RTMatrix.T2plus(); RPM = RTMatrix.R1plus() + RTMatrix.R2plus(); TMM = RTMatrix.T1min() + RTMatrix.T2min(); @@ -114,8 +114,8 @@ TEST_F(SpecularMagneticOldTest, zerofield) { RMS = RTScalar.R1min() + RTScalar.R2min(); coeffs_zerofield = - std::make_unique<SpecularMagneticOldStrategy>()->Execute(sample_zerofield.slices(), k3); - RTMatrix = *dynamic_cast<const MatrixRTCoefficients*>(coeffs_zerofield[1].get()); + std::make_unique<SpecularMagneticStrategy_v1>()->Execute(sample_zerofield.slices(), k3); + RTMatrix = *dynamic_cast<const MatrixRTCoefficients_v1*>(coeffs_zerofield[1].get()); TPM = RTMatrix.T1plus() + RTMatrix.T2plus(); RPM = RTMatrix.R1plus() + RTMatrix.R2plus(); TMM = RTMatrix.T1min() + RTMatrix.T2min();