diff --git a/Core/Multilayer/DecouplingApproximationStrategy.cpp b/Core/Multilayer/DecouplingApproximationStrategy.cpp index af67ad404e2bb89dd7ff088880ccda7336a7298f..86cce6ffbee0e0404441a3575c6feca88ec6500a 100644 --- a/Core/Multilayer/DecouplingApproximationStrategy.cpp +++ b/Core/Multilayer/DecouplingApproximationStrategy.cpp @@ -30,8 +30,9 @@ double DecouplingApproximationStrategy1::evaluateForList( { double intensity = 0.0; complex_t amplitude = complex_t(0.0, 0.0); + auto precomputed_ff = precomputeScalar(sim_element, m_formfactor_wrappers); for (size_t i = 0; i < m_formfactor_wrappers.size(); ++i) { - complex_t ff = m_precomputed_ff1[i]; + complex_t ff = precomputed_ff[i]; if (std::isnan(ff.real())) throw Exceptions::RuntimeErrorException( "DecouplingApproximationStrategy::evaluateForList() -> Error! Amplitude is NaN"); @@ -55,8 +56,9 @@ double DecouplingApproximationStrategy2::evaluateForList( Eigen::Matrix2cd mean_intensity = Eigen::Matrix2cd::Zero(); Eigen::Matrix2cd mean_amplitude = Eigen::Matrix2cd::Zero(); + auto precomputed_ff = precomputePolarized(sim_element, m_formfactor_wrappers); for (size_t i = 0; i < m_formfactor_wrappers.size(); ++i) { - Eigen::Matrix2cd ff = m_precomputed_ff2[i]; + Eigen::Matrix2cd ff = precomputed_ff[i]; if (!ff.allFinite()) throw Exceptions::RuntimeErrorException( "DecouplingApproximationStrategy::evaluateForList() -> " diff --git a/Core/Multilayer/DecouplingApproximationStrategy.h b/Core/Multilayer/DecouplingApproximationStrategy.h index 951b97b37238303863a74cd9202039ac97b423a4..d44308a162ed35eb9bd23ea5b494db6a9365bad0 100644 --- a/Core/Multilayer/DecouplingApproximationStrategy.h +++ b/Core/Multilayer/DecouplingApproximationStrategy.h @@ -25,14 +25,13 @@ class SimulationElement; //! in decoupling approximation. //! @ingroup algorithms_internal -class BA_CORE_API_ DecouplingApproximationStrategy1 final - : public IInterferenceFunctionStrategy1 +class DecouplingApproximationStrategy1 final : public IInterferenceFunctionStrategy { public: DecouplingApproximationStrategy1(SimulationOptions sim_params) - : IInterferenceFunctionStrategy1(sim_params) {} + : IInterferenceFunctionStrategy(sim_params) {} -private: +protected: double evaluateForList(const SimulationElement& sim_element) const override; }; @@ -40,14 +39,13 @@ private: //! in decoupling approximation. //! @ingroup algorithms_internal -class BA_CORE_API_ DecouplingApproximationStrategy2 final - : public IInterferenceFunctionStrategy2 +class DecouplingApproximationStrategy2 final : public IInterferenceFunctionStrategy { public: DecouplingApproximationStrategy2(SimulationOptions sim_params) - : IInterferenceFunctionStrategy2(sim_params) {} + : IInterferenceFunctionStrategy(sim_params) {} -private: +protected: double evaluateForList(const SimulationElement& sim_element) const override; }; diff --git a/Core/Multilayer/IInterferenceFunctionStrategy.cpp b/Core/Multilayer/IInterferenceFunctionStrategy.cpp index b0ad2b714f74d1cac07766ab42849a16387640b6..f723c898c1383f5342f2045f80f28f364fdbba70 100644 --- a/Core/Multilayer/IInterferenceFunctionStrategy.cpp +++ b/Core/Multilayer/IInterferenceFunctionStrategy.cpp @@ -3,8 +3,7 @@ // BornAgain: simulate and fit scattering at grazing incidence // //! @file Core/Multilayer/IInterferenceFunctionStrategy.cpp -//! @brief Implements default behaviour of IInterferenceFunctionStrategy, -//! IInterferenceFunctionStrategy1, IInterferenceFunctionStrategy2 +//! @brief Implements default behaviour of IInterferenceFunctionStrategy. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -43,7 +42,8 @@ void IInterferenceFunctionStrategy::init( const IInterferenceFunction* p_iff) { if (weighted_formfactors.size()==0) - throw Exceptions::ClassInitializationException("Bug: Decorated layer has no formfactors."); + throw Exceptions::ClassInitializationException( + "IInterferenceFunctionStrategy::init: strategy gets no formfactors."); m_formfactor_wrappers = weighted_formfactors; if (p_iff) mP_iff.reset(p_iff->clone()); @@ -57,10 +57,32 @@ double IInterferenceFunctionStrategy::evaluate(const SimulationElement& sim_elem { if (m_options.isIntegrate() && (sim_element.getSolidAngle() > 0.0)) return MCIntegratedEvaluate(sim_element); - precomputeParticleFormfactors(sim_element); return evaluateForList(sim_element); } +std::vector<complex_t> IInterferenceFunctionStrategy::precomputeScalar( + const SimulationElement& sim_element, + const SafePointerVector<FormFactorCoherentSum>& ff_wrappers) +{ + std::vector<complex_t> result; + for (auto ffw: ff_wrappers) { + result.push_back(ffw->evaluate(sim_element)); + } + return result; +} + +IInterferenceFunctionStrategy::matrixFFVector_t +IInterferenceFunctionStrategy::precomputePolarized( + const SimulationElement& sim_element, + const SafePointerVector<FormFactorCoherentSum>& ff_wrappers) +{ + matrixFFVector_t result; + for (auto ffw: ff_wrappers) { + result.push_back(ffw->evaluatePol(sim_element)); + } + return result; +} + //! Performs a Monte Carlo integration over the bin for the evaluation of the intensity. double IInterferenceFunctionStrategy::MCIntegratedEvaluate( const SimulationElement& sim_element) const @@ -80,37 +102,5 @@ double IInterferenceFunctionStrategy::evaluate_for_fixed_angles( SimulationElement* pars = static_cast<SimulationElement*>(params); SimulationElement sim_element(*pars, par0, par1); - precomputeParticleFormfactors(sim_element); return pars->getIntegrationFactor(par0, par1) * evaluateForList(sim_element); } - - -IInterferenceFunctionStrategy1::IInterferenceFunctionStrategy1( - const SimulationOptions& sim_params) - : IInterferenceFunctionStrategy(sim_params) -{} - -//! Precomputes scalar form factors. -void IInterferenceFunctionStrategy1::precomputeParticleFormfactors( - const SimulationElement& sim_element) const -{ - m_precomputed_ff1.clear(); - for (auto ffw: m_formfactor_wrappers) { - m_precomputed_ff1.push_back(ffw->evaluate(sim_element)); - } -} - -IInterferenceFunctionStrategy2::IInterferenceFunctionStrategy2( - const SimulationOptions& sim_params) - : IInterferenceFunctionStrategy(sim_params) -{} - -//! Precomputes matrix form factors. -void IInterferenceFunctionStrategy2::precomputeParticleFormfactors( - const SimulationElement& sim_element) const -{ - m_precomputed_ff2.clear(); - for (auto ffw: m_formfactor_wrappers) { - m_precomputed_ff2.push_back(ffw->evaluatePol(sim_element)); - } -} diff --git a/Core/Multilayer/IInterferenceFunctionStrategy.h b/Core/Multilayer/IInterferenceFunctionStrategy.h index 13871ec2790511cdd34f1a250da88d7975cca050..485ea9ecc652e8376c6658780e479ee698860365 100644 --- a/Core/Multilayer/IInterferenceFunctionStrategy.h +++ b/Core/Multilayer/IInterferenceFunctionStrategy.h @@ -3,8 +3,7 @@ // BornAgain: simulate and fit scattering at grazing incidence // //! @file Core/Multilayer/IInterferenceFunctionStrategy.h -//! @brief Defines classes IInterferenceFunctionStrategy, -//! IInterferenceFunctionStrategy1, IInterferenceFunctionStrategy2 +//! @brief Defines class IInterferenceFunctionStrategy. //! //! @homepage http://www.bornagainproject.org //! @license GNU General Public License v3 or higher (see COPYING) @@ -35,10 +34,9 @@ class SimulationElement; //! Base class of all interference function strategy classes. //! Provides an 'evaluate' function that computes the total scattering intensity //! from a decorated layer, taking into account a specific inter-particle interference function. -//! This function uses low-level functions precomputeParticleFormfactors, evaluateForList -//! that are implemented differently in different inheriting classes. +//! This function uses the low-level function evaluateForList +//! that is overriden in the derived classes. //! Inheritance is used to support scalar and polarized scattering -//! (through IInterferenceFunctionStrategy1, IInterferenceFunctionStrategy2) //! and to implement different approximation schemes //! (DecouplingApproximationStrategy1, SSCApproximationStrategy1, and their polarized //! counterparts). @@ -51,6 +49,9 @@ class SimulationElement; class BA_CORE_API_ IInterferenceFunctionStrategy { public: + typedef std::vector<Eigen::Matrix2cd, Eigen::aligned_allocator<Eigen::Matrix2cd>> + matrixFFVector_t; + IInterferenceFunctionStrategy(const SimulationOptions& sim_params); virtual ~IInterferenceFunctionStrategy(); @@ -62,7 +63,10 @@ public: protected: virtual void strategy_specific_post_init() {} - virtual void precomputeParticleFormfactors(const SimulationElement& sim_element) const =0; + static std::vector<complex_t> precomputeScalar(const SimulationElement& sim_element, + const SafePointerVector<FormFactorCoherentSum>& ff_wrappers); + static matrixFFVector_t precomputePolarized(const SimulationElement& sim_element, + const SafePointerVector<FormFactorCoherentSum>& ff_wrappers); //! Evaluates the intensity for given list of evaluated form factors virtual double evaluateForList(const SimulationElement& sim_element) const =0; @@ -80,33 +84,4 @@ private: #endif }; -//! Base class of all scalar interference function strategy classes. -//! Provides the precomputation of particle form factors. - -class BA_CORE_API_ IInterferenceFunctionStrategy1 : public IInterferenceFunctionStrategy -{ -public: - IInterferenceFunctionStrategy1(const SimulationOptions& sim_params); - -protected: - mutable std::vector<complex_t> m_precomputed_ff1; //!< cached form factor evaluations - void precomputeParticleFormfactors(const SimulationElement& sim_element) const final; -}; - -//! Base class of all polarized interference function strategy classes. -//! Provides the precomputation of particle form factors. - -class BA_CORE_API_ IInterferenceFunctionStrategy2 : public IInterferenceFunctionStrategy -{ -public: - IInterferenceFunctionStrategy2(const SimulationOptions& sim_params); - - typedef std::vector<Eigen::Matrix2cd, Eigen::aligned_allocator<Eigen::Matrix2cd>> - matrixFFVector_t; - -protected: - mutable matrixFFVector_t m_precomputed_ff2; //!< cached polarized form factors - void precomputeParticleFormfactors(const SimulationElement& sim_element) const final; -}; - #endif // IINTERFERENCEFUNCTIONSTRATEGY_H diff --git a/Core/Multilayer/SSCApproximationStrategy.cpp b/Core/Multilayer/SSCApproximationStrategy.cpp index f8844f3ec7d5c8cf3db07f4606f634ceec80c518..3c3413ce399699bd9e4e5dc11d0f55ac8f887f24 100644 --- a/Core/Multilayer/SSCApproximationStrategy.cpp +++ b/Core/Multilayer/SSCApproximationStrategy.cpp @@ -23,7 +23,7 @@ // ************************************************************************** // SSCApproximationStrategy1::SSCApproximationStrategy1(SimulationOptions sim_params, double kappa) - : IInterferenceFunctionStrategy1(sim_params) + : IInterferenceFunctionStrategy(sim_params) , m_helper(kappa) {} @@ -39,27 +39,29 @@ double SSCApproximationStrategy1::evaluateForList(const SimulationElement& sim_e { double qp = sim_element.getMeanQ().magxy(); double diffuse_intensity = 0.0; + auto precomputed_ff = precomputeScalar(sim_element, m_formfactor_wrappers); for (size_t i = 0; i < m_formfactor_wrappers.size(); ++i) { - complex_t ff = m_precomputed_ff1[i]; + complex_t ff = precomputed_ff[i]; double fraction = m_formfactor_wrappers[i]->relativeAbundance(); diffuse_intensity += fraction * std::norm(ff); } - complex_t mean_ff_norm = getMeanFormfactorNorm(qp); + complex_t mean_ff_norm = getMeanFormfactorNorm(qp, precomputed_ff); complex_t p2kappa = m_helper.getCharacteristicSizeCoupling(qp, m_formfactor_wrappers); complex_t omega = m_helper.getCharacteristicDistribution(qp, mP_iff.get()); double interference_intensity = 2.0 * (mean_ff_norm * omega / (1.0 - p2kappa * omega)).real(); return diffuse_intensity + interference_intensity; } -complex_t SSCApproximationStrategy1::getMeanFormfactorNorm(double qp) const +complex_t SSCApproximationStrategy1::getMeanFormfactorNorm( + double qp, const std::vector<complex_t>& precomputed_ff) const { complex_t ff_orig=0., ff_conj=0.; // original and conjugated mean formfactor for (size_t i = 0; i < m_formfactor_wrappers.size(); ++i) { double radial_extension = m_formfactor_wrappers[i]->radialExtension(); complex_t prefac = m_formfactor_wrappers[i]->relativeAbundance() * m_helper.calculatePositionOffsetPhase(qp, radial_extension); - ff_orig += prefac * m_precomputed_ff1[i]; - ff_conj += prefac * std::conj(m_precomputed_ff1[i]); + ff_orig += prefac * precomputed_ff[i]; + ff_conj += prefac * std::conj(precomputed_ff[i]); } return ff_orig * ff_conj; } @@ -69,7 +71,7 @@ complex_t SSCApproximationStrategy1::getMeanFormfactorNorm(double qp) const // ************************************************************************** // SSCApproximationStrategy2::SSCApproximationStrategy2(SimulationOptions sim_params, double kappa) - : IInterferenceFunctionStrategy2(sim_params) + : IInterferenceFunctionStrategy(sim_params) , m_helper(kappa) {} @@ -87,13 +89,14 @@ double SSCApproximationStrategy2::evaluateForList(const SimulationElement& sim_e { double qp = sim_element.getMeanQ().magxy(); Eigen::Matrix2cd diffuse_matrix = Eigen::Matrix2cd::Zero(); + auto precomputed_ff = precomputePolarized(sim_element, m_formfactor_wrappers); for (size_t i = 0; i < m_formfactor_wrappers.size(); ++i) { - Eigen::Matrix2cd ff = m_precomputed_ff2[i]; + Eigen::Matrix2cd ff = precomputed_ff[i]; double fraction = m_formfactor_wrappers[i]->relativeAbundance(); diffuse_matrix += fraction * (ff * sim_element.getPolarization() * ff.adjoint()); } Eigen::Matrix2cd mff_orig, mff_conj; // original and conjugated mean formfactor - getMeanFormfactors(qp, mff_orig, mff_conj); + getMeanFormfactors(qp, mff_orig, mff_conj, precomputed_ff); complex_t p2kappa = m_helper.getCharacteristicSizeCoupling(qp, m_formfactor_wrappers); complex_t omega = m_helper.getCharacteristicDistribution(qp, mP_iff.get()); Eigen::Matrix2cd interference_matrix @@ -108,7 +111,8 @@ double SSCApproximationStrategy2::evaluateForList(const SimulationElement& sim_e //! Computes ff_orig and ff_conj. void SSCApproximationStrategy2::getMeanFormfactors( - double qp, Eigen::Matrix2cd& ff_orig, Eigen::Matrix2cd& ff_conj) const + double qp, Eigen::Matrix2cd& ff_orig, Eigen::Matrix2cd& ff_conj, + const matrixFFVector_t& precomputed_ff) const { ff_orig=Eigen::Matrix2cd::Zero(); ff_conj=Eigen::Matrix2cd::Zero(); @@ -116,7 +120,7 @@ void SSCApproximationStrategy2::getMeanFormfactors( double radial_extension = m_formfactor_wrappers[i]->radialExtension(); complex_t prefac = m_formfactor_wrappers[i]->relativeAbundance() * m_helper.calculatePositionOffsetPhase(qp, radial_extension); - ff_orig += prefac * m_precomputed_ff2[i]; - ff_conj += prefac * m_precomputed_ff2[i].adjoint(); + ff_orig += prefac * precomputed_ff[i]; + ff_conj += prefac * precomputed_ff[i].adjoint(); } } diff --git a/Core/Multilayer/SSCApproximationStrategy.h b/Core/Multilayer/SSCApproximationStrategy.h index 332edd3d7cb74182db9c6c4805cb723809fb517d..9b20ba41b552f1f26b855615678d50164ce2786d 100644 --- a/Core/Multilayer/SSCApproximationStrategy.h +++ b/Core/Multilayer/SSCApproximationStrategy.h @@ -25,7 +25,7 @@ class SimulationElement; //! in size-spacing correlation approximation. //! @ingroup algorithms_internal -class SSCApproximationStrategy1 final : public IInterferenceFunctionStrategy1 +class SSCApproximationStrategy1 final : public IInterferenceFunctionStrategy { public: SSCApproximationStrategy1(SimulationOptions sim_params, double kappa); @@ -35,7 +35,7 @@ protected: double evaluateForList(const SimulationElement& sim_element) const override; private: - complex_t getMeanFormfactorNorm(double qp) const; + complex_t getMeanFormfactorNorm(double qp, const std::vector<complex_t>& precomputed_ff) const; SSCAHelper m_helper; }; @@ -44,7 +44,7 @@ private: //! in size-spacing correlation approximation. //! @ingroup algorithms_internal -class SSCApproximationStrategy2 final : public IInterferenceFunctionStrategy2 +class SSCApproximationStrategy2 final : public IInterferenceFunctionStrategy { public: SSCApproximationStrategy2(SimulationOptions sim_params, double kappa); @@ -54,7 +54,8 @@ protected: double evaluateForList(const SimulationElement& sim_element) const override; private: - void getMeanFormfactors(double qp, Eigen::Matrix2cd& ff_orig, Eigen::Matrix2cd& ff_conj) const; + void getMeanFormfactors(double qp, Eigen::Matrix2cd& ff_orig, Eigen::Matrix2cd& ff_conj, + const matrixFFVector_t& precomputed_ff) const; SSCAHelper m_helper; };