diff --git a/Core/Export/SampleToPython.cpp b/Core/Export/SampleToPython.cpp index 7ac385260f4ab0a44206b8a0c15a93e6e1008a93..607b37c131b483d5579127858b2750e57f6ae0a6 100644 --- a/Core/Export/SampleToPython.cpp +++ b/Core/Export/SampleToPython.cpp @@ -556,17 +556,17 @@ std::string SampleToPython::defineMultiLayers() const if (numberOfLayers) { result << indent() << key << ".addLayer(" << m_objs->obj2key(s->layer(0)) << ")\n"; - size_t layerIndex = 1; - while (layerIndex != numberOfLayers) { - const LayerInterface* layerInterface = s->layerInterface(layerIndex - 1); + size_t iLayer = 1; + while (iLayer != numberOfLayers) { + const LayerInterface* layerInterface = s->layerInterface(iLayer - 1); if (const LayerRoughness* rough = layerInterface->getRoughness()) result << indent() << key << ".addLayerWithTopRoughness(" - << m_objs->obj2key(s->layer(layerIndex)) << ", " + << m_objs->obj2key(s->layer(iLayer)) << ", " << m_objs->obj2key(rough) << ")\n"; else result << indent() << key << ".addLayer(" - << m_objs->obj2key(s->layer(layerIndex)) << ")\n"; - layerIndex++; + << m_objs->obj2key(s->layer(iLayer)) << ")\n"; + iLayer++; } } result << "\n" << indent() << "return " << key << "\n"; diff --git a/GUI/Models/GUIDomainSampleVisitor.cpp b/GUI/Models/GUIDomainSampleVisitor.cpp index edaf34d5ce0a9ffc2e97670d72ae02355c4f7933..f01dd644c0e6e41b2de83cd3bad466acac7d987a 100644 --- a/GUI/Models/GUIDomainSampleVisitor.cpp +++ b/GUI/Models/GUIDomainSampleVisitor.cpp @@ -109,9 +109,9 @@ void GUIDomainSampleVisitor::visit(const Layer* sample) const auto* multilayer = dynamic_cast<const MultiLayer*>(m_itemToSample[parent]); ASSERT(multilayer); - size_t layer_index = SampleUtils::Multilayer::IndexOfLayer(*multilayer, sample); + size_t iLayer = SampleUtils::Multilayer::IndexOfLayer(*multilayer, sample); const LayerInterface* top_interface = - layer_index == 0 ? nullptr : multilayer->layerInterface(layer_index - 1); + iLayer == 0 ? nullptr : multilayer->layerInterface(iLayer - 1); LayerItem* layer_item = m_sampleModel->insertItem<LayerItem>(parent); layer_item->setMaterial(createMaterialFromDomain(sample->material())); diff --git a/Resample/Coherence/FFSum.cpp b/Resample/Coherence/FFSum.cpp index 76c04b791c8aa4595f7528dbd998f0e325366ad9..422a5fb02007cf88dc2b54e55ecc65d03e9ae8ea 100644 --- a/Resample/Coherence/FFSum.cpp +++ b/Resample/Coherence/FFSum.cpp @@ -14,35 +14,28 @@ #include "Resample/Coherence/FFSum.h" -CoherentFFSum::CoherentFFSum(double abundance, const std::vector<CoherentFFTerm>& parts) - : m_abundance(abundance), m_parts(parts) +CoherentFFSum::CoherentFFSum(double abundance, const std::vector<CoherentFFTerm>& terms) + : m_abundance(abundance), m_terms(terms) { } complex_t CoherentFFSum::summedFF(const SimulationElement& sim_element) const { complex_t result = 0.; - for (const auto& part : m_parts) - result += part.coherentFF(sim_element); + for (const auto& term : m_terms) + result += term.coherentFF(sim_element); return result; } Eigen::Matrix2cd CoherentFFSum::summedPolFF(const SimulationElement& sim_element) const { Eigen::Matrix2cd result = Eigen::Matrix2cd::Zero(); - for (const auto& part : m_parts) - result += part.coherentPolFF(sim_element); + for (const auto& term : m_terms) + result += term.coherentPolFF(sim_element); return result; } -void CoherentFFSum::scaleRelativeAbundance(double total_abundance) -{ - if (total_abundance <= 0.0) - throw std::runtime_error("bug or invalid API call: nonpositiv particle abundance"); - m_abundance /= total_abundance; -} - double CoherentFFSum::radialExtension() const { - return m_parts[0].radialExtension(); + return m_terms[0].radialExtension(); } diff --git a/Resample/Coherence/FFSum.h b/Resample/Coherence/FFSum.h index e4aac16925e14f658d85e2f750767a01351c93c7..100e38bf159d3b0dbc15f7183de73272093fd2a4 100644 --- a/Resample/Coherence/FFSum.h +++ b/Resample/Coherence/FFSum.h @@ -30,18 +30,17 @@ class SimulationElement; class CoherentFFSum { public: - CoherentFFSum(double abundance, const std::vector<CoherentFFTerm>& parts); + CoherentFFSum(double abundance, const std::vector<CoherentFFTerm>& terms); complex_t summedFF(const SimulationElement& sim_element) const; Eigen::Matrix2cd summedPolFF(const SimulationElement& sim_element) const; double relativeAbundance() const { return m_abundance; } - void scaleRelativeAbundance(double total_abundance); double radialExtension() const; private: - double m_abundance; - const std::vector<CoherentFFTerm> m_parts; + const double m_abundance; + const std::vector<CoherentFFTerm> m_terms; }; #endif // BORNAGAIN_RESAMPLE_COHERENCE_FFSUM_H diff --git a/Resample/Coherence/FFTerm.cpp b/Resample/Coherence/FFTerm.cpp index d00be6a365fd3f8b47dae5b4a041642364fe7552..540490ba58aa3c4f2222f92d01a9c6f1c9102852 100644 --- a/Resample/Coherence/FFTerm.cpp +++ b/Resample/Coherence/FFTerm.cpp @@ -13,20 +13,15 @@ // ************************************************************************************************ #include "Resample/Coherence/FFTerm.h" -#include "Base/Pixel/SimulationElement.h" -#include "Base/Utils/Assert.h" #include "Resample/FFCompute/IComputeFF.h" -#include "Resample/Flux/IFlux.h" -#include "Resample/Fresnel/IFresnelMap.h" -#include "Sample/Material/WavevectorInfo.h" -CoherentFFTerm::CoherentFFTerm(IComputeFF* ff, size_t layer_index) - : m_ff(ff), m_layer_index(layer_index) +CoherentFFTerm::CoherentFFTerm(IComputeFF* computer) + : m_computer(computer) { } CoherentFFTerm::CoherentFFTerm(const CoherentFFTerm& other) - : m_ff(std::unique_ptr<IComputeFF>(other.m_ff->clone())), m_layer_index(other.m_layer_index) + : m_computer(std::unique_ptr<IComputeFF>(other.m_computer->clone())) { } @@ -34,25 +29,15 @@ CoherentFFTerm::~CoherentFFTerm() = default; complex_t CoherentFFTerm::coherentFF(const SimulationElement& ele) const { - const IFresnelMap* const fresnel_map = ele.fresnelMap(); - ASSERT(fresnel_map); - auto inFlux = fresnel_map->getInFlux(ele.getKi(), m_layer_index); - auto outFlux = fresnel_map->getOutFlux(ele.getMeanKf(), m_layer_index); - m_ff->setFlux(std::move(inFlux), std::move(outFlux)); - return m_ff->computeFF({ele}); + return m_computer->coherentFF(ele); } Eigen::Matrix2cd CoherentFFTerm::coherentPolFF(const SimulationElement& ele) const { - const IFresnelMap* const fresnel_map = ele.fresnelMap(); - ASSERT(fresnel_map); - auto inFlux = fresnel_map->getInFlux(ele.getKi(), m_layer_index); - auto outFlux = fresnel_map->getOutFlux(ele.getMeanKf(), m_layer_index); - m_ff->setFlux(std::move(inFlux), std::move(outFlux)); - return m_ff->computePolFF({ele}); + return m_computer->coherentPolFF(ele); } double CoherentFFTerm::radialExtension() const { - return m_ff->radialExtension(); + return m_computer->radialExtension(); } diff --git a/Resample/Coherence/FFTerm.h b/Resample/Coherence/FFTerm.h index e4fe49bd3130fe448309a7c1715c000307557ad0..7d6e3770eea4691ac82d58fff991589810f9f418 100644 --- a/Resample/Coherence/FFTerm.h +++ b/Resample/Coherence/FFTerm.h @@ -32,7 +32,7 @@ class SimulationElement; class CoherentFFTerm { public: - CoherentFFTerm(IComputeFF* ff, size_t layer_index); + CoherentFFTerm(IComputeFF* computer); CoherentFFTerm(const CoherentFFTerm& other); CoherentFFTerm& operator=(const CoherentFFTerm& other) = delete; ~CoherentFFTerm(); @@ -43,8 +43,7 @@ public: double radialExtension() const; private: - const std::unique_ptr<IComputeFF> m_ff; - const size_t m_layer_index; + const std::unique_ptr<IComputeFF> m_computer; }; #endif // BORNAGAIN_RESAMPLE_COHERENCE_FFTERM_H diff --git a/Resample/FFCompute/ComputeBA.cpp b/Resample/FFCompute/ComputeBA.cpp index 507049659b4c21fbe4bd3a7c229af0a3e017ff24..028b556ebddbd4707e1f54eac922eec8f7c94e2d 100644 --- a/Resample/FFCompute/ComputeBA.cpp +++ b/Resample/FFCompute/ComputeBA.cpp @@ -16,13 +16,13 @@ #include "Sample/Material/WavevectorInfo.h" #include "Sample/Scattering/IFormFactor.h" -ComputeBA::ComputeBA(const IFormFactor& ff) : IComputeFF(ff) {} +ComputeBA::ComputeBA(const IFormFactor& ff, size_t iLayer) : IComputeFF(ff, iLayer) {} ComputeBA::~ComputeBA() = default; ComputeBA* ComputeBA::clone() const { - return new ComputeBA(*m_ff); + return new ComputeBA(*m_ff, m_iLayer); } complex_t ComputeBA::computeFF(const WavevectorInfo& wavevectors) const diff --git a/Resample/FFCompute/ComputeBA.h b/Resample/FFCompute/ComputeBA.h index ffd58c6c743091319be3717d9c7c88a4517f7009..7f8ccc572f3e907ad6a2a31c48e290f0da66851c 100644 --- a/Resample/FFCompute/ComputeBA.h +++ b/Resample/FFCompute/ComputeBA.h @@ -29,7 +29,7 @@ class ComputeBA : public IComputeFF { public: - ComputeBA(const IFormFactor& ff); + ComputeBA(const IFormFactor& ff, size_t iLayer); ~ComputeBA() override; ComputeBA* clone() const override; diff --git a/Resample/FFCompute/ComputeBAPol.cpp b/Resample/FFCompute/ComputeBAPol.cpp index 18459c67f3a396a894b4023b2d5ab918946fc597..13ccfa43e250bf672d1058a8022bbb26581327c2 100644 --- a/Resample/FFCompute/ComputeBAPol.cpp +++ b/Resample/FFCompute/ComputeBAPol.cpp @@ -16,13 +16,13 @@ #include "Sample/Material/WavevectorInfo.h" #include <stdexcept> -ComputeBAPol::ComputeBAPol(const IFormFactor& ff) : IComputeFF(ff) {} +ComputeBAPol::ComputeBAPol(const IFormFactor& ff, size_t iLayer) : IComputeFF(ff, iLayer) {} ComputeBAPol::~ComputeBAPol() = default; ComputeBAPol* ComputeBAPol::clone() const { - return new ComputeBAPol(*m_ff); + return new ComputeBAPol(*m_ff, m_iLayer); } complex_t ComputeBAPol::computeFF(const WavevectorInfo&) const diff --git a/Resample/FFCompute/ComputeBAPol.h b/Resample/FFCompute/ComputeBAPol.h index 9643a1175f1242f2fc23cec9250aeee631f08fa1..13b27e643060b953c837cd935dca2a1fee099dc8 100644 --- a/Resample/FFCompute/ComputeBAPol.h +++ b/Resample/FFCompute/ComputeBAPol.h @@ -30,7 +30,7 @@ class ComputeBAPol : public IComputeFF { public: - ComputeBAPol(const IFormFactor& ff); + ComputeBAPol(const IFormFactor& ff, size_t iLayer); ~ComputeBAPol() override; ComputeBAPol* clone() const override; diff --git a/Resample/FFCompute/ComputeDWBA.cpp b/Resample/FFCompute/ComputeDWBA.cpp index 2703478d773068b756fba7e2f030fbacceb8629c..83381a5a9801bad2dedeea6e0a4db551d4fb83ff 100644 --- a/Resample/FFCompute/ComputeDWBA.cpp +++ b/Resample/FFCompute/ComputeDWBA.cpp @@ -17,13 +17,13 @@ #include "Sample/Material/WavevectorInfo.h" #include "Sample/Scattering/IFormFactor.h" -ComputeDWBA::ComputeDWBA(const IFormFactor& ff) : IComputeFF(ff) {} +ComputeDWBA::ComputeDWBA(const IFormFactor& ff, size_t iLayer) : IComputeFF(ff, iLayer) {} ComputeDWBA::~ComputeDWBA() = default; ComputeDWBA* ComputeDWBA::clone() const { - ComputeDWBA* result = new ComputeDWBA(*m_ff); + ComputeDWBA* result = new ComputeDWBA(*m_ff, m_iLayer); auto in_coefs = std::unique_ptr<const IFlux>(m_inFlux ? m_inFlux->clone() : nullptr); auto out_coefs = std::unique_ptr<const IFlux>(m_outFlux ? m_outFlux->clone() : nullptr); result->setFlux(std::move(in_coefs), std::move(out_coefs)); diff --git a/Resample/FFCompute/ComputeDWBA.h b/Resample/FFCompute/ComputeDWBA.h index f57cb1e6e8cc4c254e4e460c7f20a826f147d2fe..bf6910ffb2e5daeff17c6f299402a9890cea549b 100644 --- a/Resample/FFCompute/ComputeDWBA.h +++ b/Resample/FFCompute/ComputeDWBA.h @@ -31,7 +31,7 @@ class IFlux; class ComputeDWBA : public IComputeFF { public: - ComputeDWBA(const IFormFactor& ff); + ComputeDWBA(const IFormFactor& ff, size_t iLayer); ~ComputeDWBA() override; ComputeDWBA* clone() const override; diff --git a/Resample/FFCompute/ComputeDWBAPol.cpp b/Resample/FFCompute/ComputeDWBAPol.cpp index b0f999e96279523703326b633bd9dcc9406f6431..9de9bc273d97f4d0ae318ab0a43fb4edac2258f4 100644 --- a/Resample/FFCompute/ComputeDWBAPol.cpp +++ b/Resample/FFCompute/ComputeDWBAPol.cpp @@ -18,20 +18,23 @@ #include "Sample/Scattering/IFormFactor.h" namespace { + complex_t VecMatVecProduct(const Eigen::Vector2cd& vec1, const Eigen::Matrix2cd& ff, const Eigen::Vector2cd& vec2) { return vec1.transpose() * ff * vec2; } + } // namespace -ComputeDWBAPol::ComputeDWBAPol(const IFormFactor& ff) : IComputeFF(ff) {} + +ComputeDWBAPol::ComputeDWBAPol(const IFormFactor& ff, size_t iLayer) : IComputeFF(ff, iLayer) {} ComputeDWBAPol::~ComputeDWBAPol() = default; ComputeDWBAPol* ComputeDWBAPol::clone() const { - ComputeDWBAPol* result = new ComputeDWBAPol(*m_ff); + ComputeDWBAPol* result = new ComputeDWBAPol(*m_ff, m_iLayer); std::unique_ptr<const IFlux> in_coefs = m_inFlux ? std::unique_ptr<const IFlux>(m_inFlux->clone()) : nullptr; std::unique_ptr<const IFlux> out_coefs = diff --git a/Resample/FFCompute/ComputeDWBAPol.h b/Resample/FFCompute/ComputeDWBAPol.h index f340059e431ad1e5c0cd2558434f459f53abde08..d8524d080d66fa9d6261adcbb788ba70d7fbd448 100644 --- a/Resample/FFCompute/ComputeDWBAPol.h +++ b/Resample/FFCompute/ComputeDWBAPol.h @@ -31,7 +31,7 @@ class IFlux; class ComputeDWBAPol : public IComputeFF { public: - ComputeDWBAPol(const IFormFactor& ff); + ComputeDWBAPol(const IFormFactor& ff, size_t iLayer); ~ComputeDWBAPol() override; ComputeDWBAPol* clone() const override; diff --git a/Resample/FFCompute/IComputeFF.cpp b/Resample/FFCompute/IComputeFF.cpp index a4185d1b4fb183ab404f6dfacff22518409c4a5f..e13c607f6dbda5d5e46b799c7c0bcbf715532425 100644 --- a/Resample/FFCompute/IComputeFF.cpp +++ b/Resample/FFCompute/IComputeFF.cpp @@ -13,11 +13,16 @@ // ************************************************************************************************ #include "Resample/FFCompute/IComputeFF.h" +#include "Base/Pixel/SimulationElement.h" +#include "Base/Utils/Assert.h" #include "Resample/Flux/IFlux.h" // required by VS19 compiler +#include "Resample/Fresnel/IFresnelMap.h" +#include "Sample/Material/WavevectorInfo.h" #include "Sample/Scattering/IFormFactor.h" #include <stdexcept> -IComputeFF::IComputeFF(const IFormFactor& ff) : m_ff(ff.clone()) {} +IComputeFF::IComputeFF(const IFormFactor& ff, size_t iLayer) + : m_ff(ff.clone()), m_iLayer(iLayer) {} IComputeFF::~IComputeFF() = default; @@ -52,3 +57,23 @@ Eigen::Matrix2cd IComputeFF::computePolFF(const WavevectorInfo&) const } void IComputeFF::setFlux(std::unique_ptr<const IFlux>, std::unique_ptr<const IFlux>) {} + +complex_t IComputeFF::coherentFF(const SimulationElement& ele) +{ + const IFresnelMap* const fresnel_map = ele.fresnelMap(); + ASSERT(fresnel_map); + auto inFlux = fresnel_map->getInFlux(ele.getKi(), m_iLayer); + auto outFlux = fresnel_map->getOutFlux(ele.getMeanKf(), m_iLayer); + setFlux(std::move(inFlux), std::move(outFlux)); + return computeFF({ele}); +} + +Eigen::Matrix2cd IComputeFF::coherentPolFF(const SimulationElement& ele) +{ + const IFresnelMap* const fresnel_map = ele.fresnelMap(); + ASSERT(fresnel_map); + auto inFlux = fresnel_map->getInFlux(ele.getKi(), m_iLayer); + auto outFlux = fresnel_map->getOutFlux(ele.getMeanKf(), m_iLayer); + setFlux(std::move(inFlux), std::move(outFlux)); + return computePolFF({ele}); +} diff --git a/Resample/FFCompute/IComputeFF.h b/Resample/FFCompute/IComputeFF.h index 582b32f21de6b472c67bdfb42ec31fa483f5a131..23347ae46514b7b20da1cfe3113e3bb63858cc8b 100644 --- a/Resample/FFCompute/IComputeFF.h +++ b/Resample/FFCompute/IComputeFF.h @@ -28,6 +28,7 @@ class IFormFactor; class IFlux; class IRotation; class Material; +class SimulationElement; class WavevectorInfo; //! Abstract base class for form factor evaluations. @@ -43,6 +44,8 @@ public: virtual void setAmbientMaterial(const Material& material); + size_t iLayer() const { return m_iLayer; } + virtual double volume() const; virtual double radialExtension() const; virtual double bottomZ(const IRotation& rotation) const; @@ -53,10 +56,14 @@ public: //! Sets reflection/transmission info virtual void setFlux(std::unique_ptr<const IFlux>, std::unique_ptr<const IFlux>); + complex_t coherentFF(const SimulationElement& sim_element); // TODO make const + Eigen::Matrix2cd coherentPolFF(const SimulationElement& sim_element); + protected: - IComputeFF(const IFormFactor&); + IComputeFF(const IFormFactor& ff, size_t iLayer); std::unique_ptr<IFormFactor> m_ff; + const size_t m_iLayer; }; #endif // BORNAGAIN_RESAMPLE_FFCOMPUTE_ICOMPUTEFF_H diff --git a/Resample/Flux/MatrixFlux.cpp b/Resample/Flux/MatrixFlux.cpp index 05b297c0185d889b87550814bd84f4cc58397020..5dea672e3b4a833432d6d9db5280260483a0821d 100644 --- a/Resample/Flux/MatrixFlux.cpp +++ b/Resample/Flux/MatrixFlux.cpp @@ -16,10 +16,19 @@ #include "Base/Utils/Assert.h" namespace { -complex_t GetImExponential(complex_t exponent); + const auto eps = std::numeric_limits<double>::epsilon() * 10.; + +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 + MatrixFlux::MatrixFlux(double kz_sign, Eigen::Vector2cd eigenvalues, kvector_t b, double magnetic_SLD) : m_kz_sign(kz_sign) @@ -164,12 +173,3 @@ Eigen::Matrix2cd MatrixFlux::computeDeltaMatrix(double thickness) 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/Resample/Flux/ScalarFlux.cpp b/Resample/Flux/ScalarFlux.cpp index b5ea913e7d993221cd2db07240e51392714e9e2b..82cc50995b516e73148fc95a6cccc4563cb5ee0d 100644 --- a/Resample/Flux/ScalarFlux.cpp +++ b/Resample/Flux/ScalarFlux.cpp @@ -15,7 +15,9 @@ #include "Resample/Flux/ScalarFlux.h" ScalarFlux::ScalarFlux(complex_t kz, Eigen::Vector2cd TR) - : m_kz(kz), m_TR(TR), m_plus(1, 0), m_min(0, 1) {} + : m_kz(kz), m_TR(TR), m_plus(1, 0), m_min(0, 1) +{ +} ScalarFlux* ScalarFlux::clone() const { diff --git a/Resample/Fresnel/IFresnelMap.h b/Resample/Fresnel/IFresnelMap.h index 483cb71b943050edea0210adfd920ab402bdfd92..4e6e26355f7e91b27b7a2a6fc9d458caab7c2ef3 100644 --- a/Resample/Fresnel/IFresnelMap.h +++ b/Resample/Fresnel/IFresnelMap.h @@ -41,11 +41,11 @@ public: //! Retrieves the amplitude coefficients for given wavevector and layer. virtual std::unique_ptr<const IFlux> getInFlux(const kvector_t& kvec, - size_t layer_index) const = 0; + size_t iLayer) const = 0; //! Retrieves the amplitude coefficients for a (time-reversed) outgoing wavevector. virtual std::unique_ptr<const IFlux> getOutFlux(const kvector_t& kvec, - size_t layer_index) const = 0; + size_t iLayer) const = 0; const SliceStack& slices() const; diff --git a/Resample/Fresnel/MatrixFresnelMap.cpp b/Resample/Fresnel/MatrixFresnelMap.cpp index 07a2a523193c5e33acc98791c6daa10b1b0b58b5..e6c8a5524a8ff334195a99304d223f265abd0e6a 100644 --- a/Resample/Fresnel/MatrixFresnelMap.cpp +++ b/Resample/Fresnel/MatrixFresnelMap.cpp @@ -39,30 +39,30 @@ size_t MatrixFresnelMap::HashKVector::operator()(const kvector_t& kvec) const no } std::unique_ptr<const IFlux> MatrixFresnelMap::getOutFlux(const kvector_t& kvec, - size_t layer_index) const + size_t iLayer) const { - return computeFlux(-kvec, layer_index, m_inverted_slices, m_hash_table_out); + return computeFlux(-kvec, iLayer, m_inverted_slices, m_hash_table_out); } std::unique_ptr<const IFlux> MatrixFresnelMap::getInFlux(const kvector_t& kvec, - size_t layer_index) const + size_t iLayer) const { - return computeFlux(kvec, layer_index, m_slices, m_hash_table_in); + return computeFlux(kvec, iLayer, m_slices, m_hash_table_in); } std::unique_ptr<const IFlux> MatrixFresnelMap::computeFlux(const kvector_t& kvec, - size_t layer_index, + size_t iLayer, const SliceStack& slices, CoefficientHash& hash_table) const { if (!m_use_cache) { const auto coeffs = m_strategy->Execute(slices, kvec); - return std::unique_ptr<const IFlux>(coeffs[layer_index]->clone()); + return std::unique_ptr<const IFlux>(coeffs[iLayer]->clone()); } // from cache auto it = hash_table.find(kvec); if (it == hash_table.end()) it = hash_table.emplace(kvec, m_strategy->Execute(slices, kvec)).first; const auto& coef_vector = it->second; - return std::unique_ptr<const IFlux>(coef_vector[layer_index]->clone()); + return std::unique_ptr<const IFlux>(coef_vector[iLayer]->clone()); } diff --git a/Resample/Fresnel/MatrixFresnelMap.h b/Resample/Fresnel/MatrixFresnelMap.h index 432275b88e790ac839e0267b40b74fc4c0f65b21..5985232c847b4431b65ba661762518934f36ca77 100644 --- a/Resample/Fresnel/MatrixFresnelMap.h +++ b/Resample/Fresnel/MatrixFresnelMap.h @@ -49,13 +49,13 @@ private: }; std::unique_ptr<const IFlux> getInFlux(const kvector_t& kvec, - size_t layer_index) const override; + size_t iLayer) const override; std::unique_ptr<const IFlux> getOutFlux(const kvector_t& kvec, - size_t layer_index) const override; + size_t iLayer) const override; using CoefficientHash = std::unordered_map<kvector_t, ISpecularStrategy::coeffs_t, HashKVector>; - std::unique_ptr<const IFlux> computeFlux(const kvector_t& kvec, size_t layer_index, + std::unique_ptr<const IFlux> computeFlux(const kvector_t& kvec, size_t iLayer, const SliceStack& slices, CoefficientHash& hash_table) const; SliceStack m_inverted_slices; diff --git a/Resample/Fresnel/ScalarFresnelMap.cpp b/Resample/Fresnel/ScalarFresnelMap.cpp index 29b12a9a157bc410852acb4e3fc3c885ce46d09a..c3cc474e02cdeff0e6fb10e7e4720af564022c57 100644 --- a/Resample/Fresnel/ScalarFresnelMap.cpp +++ b/Resample/Fresnel/ScalarFresnelMap.cpp @@ -32,17 +32,17 @@ ScalarFresnelMap::Hash2Doubles::operator()(const std::pair<double, double>& doub } std::unique_ptr<const IFlux> ScalarFresnelMap::getOutFlux(const kvector_t& kvec, - size_t layer_index) const + size_t iLayer) const { - return getInFlux(-kvec, layer_index); + return getInFlux(-kvec, iLayer); } std::unique_ptr<const IFlux> ScalarFresnelMap::getInFlux(const kvector_t& kvec, - size_t layer_index) const + size_t iLayer) const { if (!m_use_cache) { auto coeffs = m_strategy->Execute(m_slices, kvec); - return std::unique_ptr<const IFlux>(coeffs[layer_index]->clone()); + return std::unique_ptr<const IFlux>(coeffs[iLayer]->clone()); } // from cache std::pair<double, double> k2_theta(kvec.mag2(), kvec.theta()); @@ -50,5 +50,5 @@ std::unique_ptr<const IFlux> ScalarFresnelMap::getInFlux(const kvector_t& kvec, if (it == m_cache.end()) it = m_cache.emplace(k2_theta, m_strategy->Execute(m_slices, kvec)).first; const auto& coef_vector = it->second; - return std::unique_ptr<const IFlux>(coef_vector[layer_index]->clone()); + return std::unique_ptr<const IFlux>(coef_vector[iLayer]->clone()); } diff --git a/Resample/Fresnel/ScalarFresnelMap.h b/Resample/Fresnel/ScalarFresnelMap.h index acf3059209c22f3b576b76e25038580fc617b213..fb42c647f2b4f945cf8ab6e7d854c055e32efd60 100644 --- a/Resample/Fresnel/ScalarFresnelMap.h +++ b/Resample/Fresnel/ScalarFresnelMap.h @@ -49,9 +49,9 @@ private: }; std::unique_ptr<const IFlux> getInFlux(const kvector_t& kvec, - size_t layer_index) const override; + size_t iLayer) const override; std::unique_ptr<const IFlux> getOutFlux(const kvector_t& kvec, - size_t layer_index) const override; + size_t iLayer) const override; mutable std::unordered_map<std::pair<double, double>, ISpecularStrategy::coeffs_t, Hash2Doubles> m_cache; diff --git a/Resample/Interparticle/DecouplingApproximationStrategy.cpp b/Resample/Interparticle/DecouplingApproximationStrategy.cpp index 9bce860086040b502f118d390b18c423869eb12f..2bfd4979f94b97006d78367f96cde7a76bc24e0a 100644 --- a/Resample/Interparticle/DecouplingApproximationStrategy.cpp +++ b/Resample/Interparticle/DecouplingApproximationStrategy.cpp @@ -39,7 +39,7 @@ DecouplingApproximationStrategy::scalarCalculation(const SimulationElement& sim_ const complex_t ff = ffw.summedFF(sim_element); if (std::isnan(ff.real())) throw std::runtime_error( - "DecouplingApproximationStrategy::scalarCalculation() -> Error! Amplitude is NaN"); + "numerical error in coherent sum (scalar, DA): amplitude is NaN"); double fraction = ffw.relativeAbundance(); amplitude += fraction * ff; intensity += fraction * std::norm(ff); @@ -60,8 +60,8 @@ DecouplingApproximationStrategy::polarizedCalculation(const SimulationElement& s for (const auto& ffw : m_weighted_formfactors) { const Eigen::Matrix2cd ff = ffw.summedPolFF(sim_element); if (!ff.allFinite()) - throw std::runtime_error("DecouplingApproximationStrategy::polarizedCalculation() -> " - "Error! Form factor contains NaN or infinite"); + throw std::runtime_error( + "numerical error in coherent sum (polarized, DA): amplitude is NaN"); const double fraction = ffw.relativeAbundance(); mean_amplitude += fraction * ff; mean_intensity += fraction * (ff * polarization_handler.getPolarization() * ff.adjoint()); diff --git a/Resample/Processed/ParticleRegions.cpp b/Resample/Processed/ParticleRegions.cpp index d85e19bf56fc662f6399aef05d6925dff90236eb..1c91f80a2331b3d18267f0b3bf45601d629148dc 100644 --- a/Resample/Processed/ParticleRegions.cpp +++ b/Resample/Processed/ParticleRegions.cpp @@ -45,8 +45,8 @@ public: std::vector<ZLimits> layerZLimits() const; private: - size_t layerIndexTop(double top_z) const; - size_t layerIndexBottom(double bottom_z) const; + size_t iLayerTop(double top_z) const; + size_t iLayerBottom(double bottom_z) const; void updateLayerLimits(size_t i_layer, ZLimits limits); std::vector<double> m_layers_bottomz; std::vector<ZLimits> m_layer_fill_limits; @@ -99,8 +99,8 @@ void LayerFillLimits::update(ZLimits particle_limits, double offset) throw std::runtime_error("LayerFillLimits::update: lower_limit > upper_limit."); if (bottom == top) // zero-size particle return; - size_t top_index = layerIndexTop(top); - size_t bottom_index = layerIndexBottom(bottom); + size_t top_index = iLayerTop(top); + size_t bottom_index = iLayerBottom(bottom); for (size_t i_layer = top_index; i_layer < bottom_index + 1; ++i_layer) { ZLimits limits(bottom, top); updateLayerLimits(i_layer, limits); @@ -112,7 +112,7 @@ std::vector<ZLimits> LayerFillLimits::layerZLimits() const return m_layer_fill_limits; } -size_t LayerFillLimits::layerIndexTop(double top_z) const +size_t LayerFillLimits::iLayerTop(double top_z) const { if (m_layers_bottomz.empty()) return 0; @@ -122,7 +122,7 @@ size_t LayerFillLimits::layerIndexTop(double top_z) const return static_cast<size_t>(m_layers_bottomz.rend() - index_above); } -size_t LayerFillLimits::layerIndexBottom(double bottom_z) const +size_t LayerFillLimits::iLayerBottom(double bottom_z) const { if (m_layers_bottomz.empty()) return 0; diff --git a/Resample/Processed/ProcessedLayout.cpp b/Resample/Processed/ProcessedLayout.cpp index 190a266f32321594c21a659bd0f5f1552ce94d07..90b2346d3aa95a49c985a56e41f93ee633d01b06 100644 --- a/Resample/Processed/ProcessedLayout.cpp +++ b/Resample/Processed/ProcessedLayout.cpp @@ -13,6 +13,7 @@ // ************************************************************************************************ #include "Resample/Processed/ProcessedLayout.h" +#include "Base/Utils/Assert.h" #include "Resample/Coherence/FFSum.h" #include "Resample/FFCompute/ComputeBA.h" #include "Resample/FFCompute/ComputeBAPol.h" @@ -34,12 +35,11 @@ ProcessedLayout::ProcessedLayout(const ParticleLayout& layout, const SliceStack& , m_surface_density(layout.weightedParticleSurfaceDensity()) { const double layout_abundance = layout.getTotalAbundance(); - for (const auto* particle : layout.particles()) { - CoherentFFSum ff_coh = - processParticle(*particle, slices, z_ref, m_surface_density / layout_abundance); - ff_coh.scaleRelativeAbundance(layout_abundance); - m_formfactors.emplace_back(ff_coh); - } + ASSERT(layout_abundance > 0); + for (const auto* particle : layout.particles()) + m_formfactors.emplace_back( + processParticle(*particle, slices, z_ref, m_surface_density / layout_abundance, + layout_abundance)); if (const auto* iff = layout.interferenceFunction()) m_iff.reset(iff->clone()); @@ -85,7 +85,8 @@ ProcessedLayout::~ProcessedLayout() = default; //! Returns a contribution to m_formfactors, and modifies m_region_map. CoherentFFSum ProcessedLayout::processParticle(const IParticle& particle, const SliceStack& slices, - double z_ref, double intensity_factor) + double z_ref, double intensity_factor, + double total_abundance) { const double abundance = particle.abundance(); const SlicedFormFactorList sliced_ffs(particle, slices, z_ref); @@ -96,34 +97,35 @@ CoherentFFSum ProcessedLayout::processParticle(const IParticle& particle, const for (auto& region : entry.second) region.m_volume *= abundance * intensity_factor; for (const auto& entry : region_map) { - const size_t layer_index = entry.first; + const size_t iLayer = entry.first; const auto& regions = entry.second; - m_region_map[layer_index].insert(m_region_map[layer_index].begin(), regions.begin(), + m_region_map[iLayer].insert(m_region_map[iLayer].begin(), regions.begin(), regions.end()); } - std::vector<CoherentFFTerm> coherentParts; + std::vector<CoherentFFTerm> terms; for (size_t i = 0; i < sliced_ffs.size(); ++i) { // TODO provide slices_ffs.cbegin() etc - const auto ff_pair = sliced_ffs[i]; - std::unique_ptr<IComputeFF> ff_framework; + const auto pair = sliced_ffs.getPair(i); + const IFormFactor& ff = *pair.first; + const size_t iLayer = pair.second; + std::unique_ptr<IComputeFF> computer; if (slices.size() > 1) { if (m_polarized) - ff_framework = std::make_unique<ComputeDWBAPol>(*ff_pair.first); + computer = std::make_unique<ComputeDWBAPol>(ff, iLayer); else - ff_framework = std::make_unique<ComputeDWBA>(*ff_pair.first); + computer = std::make_unique<ComputeDWBA>(ff, iLayer); } else { // no need for DWBA, use BA if (m_polarized) - ff_framework = std::make_unique<ComputeBAPol>(*ff_pair.first); + computer = std::make_unique<ComputeBAPol>(ff, iLayer); else - ff_framework = std::make_unique<ComputeBA>(*ff_pair.first); + computer = std::make_unique<ComputeBA>(ff, iLayer); } - const size_t slice_index = ff_pair.second; - const Material& slice_material = slices[slice_index].material(); - ff_framework->setAmbientMaterial(slice_material); + const Material& slice_material = slices[iLayer].material(); + computer->setAmbientMaterial(slice_material); - coherentParts.emplace_back(CoherentFFTerm(ff_framework.release(), slice_index)); + terms.emplace_back(CoherentFFTerm(computer.release())); } - return CoherentFFSum(abundance, coherentParts); + return CoherentFFSum(abundance / total_abundance, terms); } diff --git a/Resample/Processed/ProcessedLayout.h b/Resample/Processed/ProcessedLayout.h index 7dc754b1f9a2387d65efbaa19da823994b34ce7b..fdbb053997651d9ba950db0feba526e7ba118ff0 100644 --- a/Resample/Processed/ProcessedLayout.h +++ b/Resample/Processed/ProcessedLayout.h @@ -54,7 +54,7 @@ public: private: CoherentFFSum processParticle(const IParticle& particle, const SliceStack& slices, double z_ref, - double intensity_factor); + double intensity_factor, double total_abundance); const bool m_polarized; const size_t m_n_slices; diff --git a/Resample/Slice/SlicedFormFactorList.cpp b/Resample/Slice/SlicedFormFactorList.cpp index ff255a792fa2cf7e7cb6ac83f822edbde51266e9..fcabcc6669ca7778354cb58486212885731263ab 100644 --- a/Resample/Slice/SlicedFormFactorList.cpp +++ b/Resample/Slice/SlicedFormFactorList.cpp @@ -67,8 +67,9 @@ void ScaleRegions(std::vector<HomogeneousRegion>& regions, double factor) } // namespace + // ************************************************************************************************ -// class SlicedFormFactorList +// class implementation // ************************************************************************************************ SlicedFormFactorList::SlicedFormFactorList(const IParticle& particle, const SliceStack& slices, @@ -111,7 +112,7 @@ size_t SlicedFormFactorList::size() const return m_ff_list.size(); } -std::pair<const IFormFactor*, size_t> SlicedFormFactorList::operator[](size_t index) const +std::pair<const IFormFactor*, size_t> SlicedFormFactorList::getPair(size_t index) const { if (index >= size()) throw std::out_of_range("SlicedFormFactorList::operator[] error: " diff --git a/Resample/Slice/SlicedFormFactorList.h b/Resample/Slice/SlicedFormFactorList.h index faf7f4838331040407c7365eb09d2085b4e573b6..4f9b78be086b04d4f752269344c5aa76e1fffd2d 100644 --- a/Resample/Slice/SlicedFormFactorList.h +++ b/Resample/Slice/SlicedFormFactorList.h @@ -42,7 +42,7 @@ public: size_t size() const; - std::pair<const IFormFactor*, size_t> operator[](size_t index) const; + std::pair<const IFormFactor*, size_t> getPair(size_t index) const; const std::map<size_t, std::vector<HomogeneousRegion>>& regionMap() const; diff --git a/Resample/Specular/SpecularScalarStrategy.cpp b/Resample/Specular/SpecularScalarStrategy.cpp index 7f2f0a530717cf26f144b050e42cf1a0e1bf956a..ad3a88a62c258d911c6bb0a98f34dfd965662d7a 100644 --- a/Resample/Specular/SpecularScalarStrategy.cpp +++ b/Resample/Specular/SpecularScalarStrategy.cpp @@ -49,7 +49,7 @@ ISpecularStrategy::coeffs_t SpecularScalarStrategy::Execute(const SliceStack& sl const std::vector<Eigen::Vector2cd> TR = computeTR(slices, kz); ISpecularStrategy::coeffs_t result; - for (size_t i = 0; i < kz.size(); ++i) + for (size_t i = 0; i < kz.size(); ++i) result.emplace_back(std::make_unique<ScalarFlux>(kz[i], TR[i])); return result; } @@ -88,8 +88,7 @@ SpecularScalarStrategy::computeTopLayerR(const SliceStack& slices, } std::vector<Eigen::Vector2cd> -SpecularScalarStrategy::computeTR(const SliceStack& slices, - const std::vector<complex_t>& kz) const +SpecularScalarStrategy::computeTR(const SliceStack& slices, const std::vector<complex_t>& kz) const { const size_t N = slices.size(); std::vector<Eigen::Vector2cd> TR(N, {1., 0.}); diff --git a/Sample/Material/MaterialFactoryFuncs.h b/Sample/Material/MaterialFactoryFuncs.h index 7a1f875437b51e6d3257903388f55168810fac02..599ca90806e22d1d373cb94371882862a29ac909 100644 --- a/Sample/Material/MaterialFactoryFuncs.h +++ b/Sample/Material/MaterialFactoryFuncs.h @@ -17,8 +17,6 @@ #include "Sample/Material/Material.h" -struct HomogeneousRegion; - //! @ingroup materials Material HomogeneousMaterial(); diff --git a/Sample/Multilayer/MultiLayer.cpp b/Sample/Multilayer/MultiLayer.cpp index 5aeceba786f4a45edda3bd399eb6c469b6783315..fcd7d32fc2971c10d442316a1ea42c0f8efe4e3e 100644 --- a/Sample/Multilayer/MultiLayer.cpp +++ b/Sample/Multilayer/MultiLayer.cpp @@ -87,7 +87,7 @@ void MultiLayer::addLayerWithTopRoughness(const Layer& layer, const LayerRoughne const Layer* MultiLayer::layer(size_t i_layer) const { - return m_layers[check_layer_index(i_layer)]; + return m_layers[check_iLayer(i_layer)]; } const LayerInterface* MultiLayer::layerInterface(size_t i_interface) const @@ -139,7 +139,7 @@ void MultiLayer::addInterface(LayerInterface* child) registerChild(child); } -size_t MultiLayer::check_layer_index(size_t i_layer) const +size_t MultiLayer::check_iLayer(size_t i_layer) const { if (i_layer >= m_layers.size()) throw std::runtime_error("Layer index is out of bounds"); diff --git a/Sample/Multilayer/MultiLayer.h b/Sample/Multilayer/MultiLayer.h index 596e28d70a697b809505669ffd83a2a8714d0af2..842b84924b87782b75b5bfd8d68876e7388b9b6c 100644 --- a/Sample/Multilayer/MultiLayer.h +++ b/Sample/Multilayer/MultiLayer.h @@ -79,7 +79,7 @@ private: void addInterface(LayerInterface* child); //! Checks index of layer w.r.t. vector length - size_t check_layer_index(size_t i_layer) const; + size_t check_iLayer(size_t i_layer) const; //! Checks index of interface w.r.t. vector length size_t check_interface_index(size_t i_interface) const; diff --git a/Tests/UnitTests/Core/Sample/FormFactorCoherentSumTest.cpp b/Tests/UnitTests/Core/Sample/FormFactorCoherentSumTest.cpp index e244d22e87182a583c17d31f8b3b59aeed5b8548..191471ca8a0f00615d2e26764500e963a4142c4d 100644 --- a/Tests/UnitTests/Core/Sample/FormFactorCoherentSumTest.cpp +++ b/Tests/UnitTests/Core/Sample/FormFactorCoherentSumTest.cpp @@ -8,14 +8,9 @@ class CoherentFFSumTest : public ::testing::Test { TEST_F(CoherentFFSumTest, RelAbundance) { - const double epsilon = 1e-12; FormFactorFullSphere ff(5.0); - CoherentFFTerm part(new ComputeBA(ff), 1.); + CoherentFFTerm part(new ComputeBA(ff, 0)); CoherentFFSum ffw(1.0, {part}); EXPECT_EQ(1.0, ffw.relativeAbundance()); EXPECT_EQ(5.0, ffw.radialExtension()); - ffw.scaleRelativeAbundance(2.0); - EXPECT_NEAR(0.5, ffw.relativeAbundance(), epsilon); - EXPECT_THROW(ffw.scaleRelativeAbundance(0.0), std::runtime_error); - EXPECT_EQ(5.0, ffw.radialExtension()); } diff --git a/mvvm/tests/testviewmodel/TestToyLayerItem.cpp b/mvvm/tests/testviewmodel/TestToyLayerItem.cpp index 3888c808b244c811092b7bf672f05e77f69b48c9..59a8a758231a063c6265ee4a0941a5cd789c2d93 100644 --- a/mvvm/tests/testviewmodel/TestToyLayerItem.cpp +++ b/mvvm/tests/testviewmodel/TestToyLayerItem.cpp @@ -67,22 +67,22 @@ TEST_F(ToyLayerItemTest, inViewModel) EXPECT_EQ(viewModel.columnCount(), 2); // accessing to viewItem representing layerItem - QModelIndex layerIndex = viewModel.index(0, 0); - auto viewItem = dynamic_cast<ViewLabelItem*>(viewModel.itemFromIndex(layerIndex)); + QModelIndex iLayer = viewModel.index(0, 0); + auto viewItem = dynamic_cast<ViewLabelItem*>(viewModel.itemFromIndex(iLayer)); EXPECT_TRUE(viewItem != nullptr); EXPECT_EQ(viewItem->item(), layerItem); // it has two rows and two columns, corresponding to our "thickness" and "color" properties - EXPECT_EQ(viewModel.rowCount(layerIndex), 2); - EXPECT_EQ(viewModel.columnCount(layerIndex), 2); + EXPECT_EQ(viewModel.rowCount(iLayer), 2); + EXPECT_EQ(viewModel.columnCount(iLayer), 2); // accessing to views representing label and value of thickness property - QModelIndex thicknessLabelIndex = viewModel.index(0, 0, layerIndex); + QModelIndex thicknessLabelIndex = viewModel.index(0, 0, iLayer); auto thicknessLabelView = dynamic_cast<ViewLabelItem*>(viewModel.itemFromIndex(thicknessLabelIndex)); EXPECT_TRUE(thicknessLabelView != nullptr); - QModelIndex thicknessValueIndex = viewModel.index(0, 1, layerIndex); + QModelIndex thicknessValueIndex = viewModel.index(0, 1, iLayer); auto thicknessValueView = dynamic_cast<ViewDataItem*>(viewModel.itemFromIndex(thicknessValueIndex)); EXPECT_TRUE(thicknessValueView != nullptr); @@ -104,8 +104,8 @@ TEST_F(ToyLayerItemTest, layerItemDataChanged) // constructing viewModel from sample model DefaultViewModel viewModel(&model); - QModelIndex layerIndex = viewModel.index(0, 0); - QModelIndex thicknessIndex = viewModel.index(0, 1, layerIndex); + QModelIndex iLayer = viewModel.index(0, 0); + QModelIndex thicknessIndex = viewModel.index(0, 1, iLayer); QSignalSpy spyDataChanged(&viewModel, &DefaultViewModel::dataChanged); diff --git a/mvvm/tests/testviewmodel/topitemsviewmodel.test.cpp b/mvvm/tests/testviewmodel/topitemsviewmodel.test.cpp index 099849ece26bb6f8b9ce6f97871c0928dbdaa55e..03f327569f09208b6e31c2bc1e91b2ac4962b761 100644 --- a/mvvm/tests/testviewmodel/topitemsviewmodel.test.cpp +++ b/mvvm/tests/testviewmodel/topitemsviewmodel.test.cpp @@ -95,23 +95,23 @@ TEST_F(TopItemsViewModelTest, insertLayerInMultiLayerThenRemove) EXPECT_EQ(spyInsert.count(), 2); // checking their indices - auto multilayer_index = viewmodel.index(0, 0, QModelIndex()); - auto layer_index = viewmodel.index(0, 0, multilayer_index); - EXPECT_EQ(viewmodel.sessionItemFromIndex(multilayer_index), multilayer); - EXPECT_EQ(viewmodel.sessionItemFromIndex(layer_index), layer); + auto multiiLayer = viewmodel.index(0, 0, QModelIndex()); + auto iLayer = viewmodel.index(0, 0, multiiLayer); + EXPECT_EQ(viewmodel.sessionItemFromIndex(multiiLayer), multilayer); + EXPECT_EQ(viewmodel.sessionItemFromIndex(iLayer), layer); // checking row and columns - EXPECT_EQ(viewmodel.rowCount(multilayer_index), 1); - EXPECT_EQ(viewmodel.columnCount(multilayer_index), 2); - EXPECT_EQ(viewmodel.rowCount(layer_index), 0); - EXPECT_EQ(viewmodel.columnCount(layer_index), 0); + EXPECT_EQ(viewmodel.rowCount(multiiLayer), 1); + EXPECT_EQ(viewmodel.columnCount(multiiLayer), 2); + EXPECT_EQ(viewmodel.rowCount(iLayer), 0); + EXPECT_EQ(viewmodel.columnCount(iLayer), 0); // removing layer model.removeItem(multilayer, {"", 0}); EXPECT_EQ(spyRemove.count(), 1); EXPECT_EQ(spyInsert.count(), 2); - EXPECT_EQ(viewmodel.rowCount(multilayer_index), 0); - EXPECT_EQ(viewmodel.columnCount(multilayer_index), 0); + EXPECT_EQ(viewmodel.rowCount(multiiLayer), 0); + EXPECT_EQ(viewmodel.columnCount(multiiLayer), 0); } //! Insert LayerItem in MultiLayer while multilayer is root item. Then deleting multilayer.