diff --git a/Doxyfile b/Doxyfile index a0e3b28..bc9cfbd 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = fourdst::libcomposition # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = v2.0.4 +PROJECT_NUMBER = v2.0.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewers a diff --git a/meson.build b/meson.build index 9fa309e..358f202 100644 --- a/meson.build +++ b/meson.build @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # *********************************************************************** # -project('libcomposition', 'cpp', version: 'v2.0.4', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0') +project('libcomposition', 'cpp', version: 'v2.0.6', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0') # Add default visibility for all C++ targets add_project_arguments('-fvisibility=default', language: 'cpp') diff --git a/src/composition/include/fourdst/composition/composition_abstract.h b/src/composition/include/fourdst/composition/composition_abstract.h index 173fd01..7e8b003 100644 --- a/src/composition/include/fourdst/composition/composition_abstract.h +++ b/src/composition/include/fourdst/composition/composition_abstract.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -180,46 +181,4 @@ namespace fourdst::composition { }; // ReSharper disable once CppClassCanBeFinal - class CompositionDecorator : public CompositionAbstract { - public: - explicit CompositionDecorator(std::unique_ptr decorator) : m_base_composition(std::move(decorator)) {}; - [[nodiscard]] bool contains(const atomic::Species &species) const noexcept override { return m_base_composition->contains(species); }; - [[nodiscard]] bool contains(const std::string& symbol) const override { return m_base_composition->contains(symbol); }; - [[nodiscard]] size_t size() const noexcept override { return m_base_composition->size(); }; - [[nodiscard]] std::set getRegisteredSymbols() const noexcept override { return m_base_composition->getRegisteredSymbols(); }; - [[nodiscard]] const std::set &getRegisteredSpecies() const noexcept override { return m_base_composition->getRegisteredSpecies(); }; - [[nodiscard]] std::unordered_map getMassFraction() const noexcept override { return m_base_composition->getMassFraction(); }; - [[nodiscard]] std::unordered_map getNumberFraction() const noexcept override { return m_base_composition->getNumberFraction(); }; - [[nodiscard]] double getMassFraction(const std::string& symbol) const override { return m_base_composition->getMassFraction(symbol); }; - [[nodiscard]] double getMassFraction(const atomic::Species& species) const override { return m_base_composition->getMassFraction(species); }; - [[nodiscard]] double getNumberFraction(const std::string& symbol) const override { return m_base_composition->getNumberFraction(symbol); }; - [[nodiscard]] double getNumberFraction(const atomic::Species& species) const override { return m_base_composition->getNumberFraction(species); }; - [[nodiscard]] double getMolarAbundance(const std::string& symbol) const override { return m_base_composition->getMolarAbundance(symbol); }; - [[nodiscard]] double getMolarAbundance(const atomic::Species& species) const override { return m_base_composition->getMolarAbundance(species); }; - [[nodiscard]] double getMeanParticleMass() const noexcept override { return m_base_composition->getMeanParticleMass(); }; - [[nodiscard]] double getElectronAbundance() const noexcept override { return m_base_composition->getElectronAbundance(); }; - [[nodiscard]] std::vector getMassFractionVector() const noexcept override { return m_base_composition->getMassFractionVector(); }; - [[nodiscard]] std::vector getNumberFractionVector() const noexcept override { return m_base_composition->getNumberFractionVector(); }; - [[nodiscard]] std::vector getMolarAbundanceVector() const noexcept override { return m_base_composition->getMolarAbundanceVector(); }; - [[nodiscard]] size_t getSpeciesIndex(const std::string& symbol) const override { return m_base_composition->getSpeciesIndex(symbol); }; - [[nodiscard]] size_t getSpeciesIndex(const atomic::Species& species) const override { return m_base_composition->getSpeciesIndex(species); }; - [[nodiscard]] atomic::Species getSpeciesAtIndex(const size_t index) const override { return m_base_composition->getSpeciesAtIndex(index); }; - [[nodiscard]] std::unique_ptr clone() const override { - return std::make_unique(m_base_composition->clone()); - } - [[nodiscard]] std::map::iterator begin() override { - return m_base_composition->begin(); - } - [[nodiscard]] std::map::iterator end() override { - return m_base_composition->end(); - } - [[nodiscard]] std::map::const_iterator begin() const override { - return std::as_const(*m_base_composition).begin(); - } - [[nodiscard]] std::map::const_iterator end() const override { - return std::as_const(*m_base_composition).end(); - } - private: - std::unique_ptr m_base_composition; - }; } \ No newline at end of file diff --git a/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h b/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h new file mode 100644 index 0000000..c3575b7 --- /dev/null +++ b/src/composition/include/fourdst/composition/decorators/composition_decorator_abstract.h @@ -0,0 +1,48 @@ +#pragma once + +#include "fourdst/atomic/atomicSpecies.h" + +#include "fourdst/composition/composition_abstract.h" + +#include +#include +#include +#include +#include + +namespace fourdst::composition { + + class CompositionDecorator: public CompositionAbstract { + public: + explicit CompositionDecorator(std::unique_ptr decorator) : m_base_composition(std::move(decorator)) {}; + [[nodiscard]] bool contains(const atomic::Species &species) const noexcept override { return m_base_composition->contains(species); }; + [[nodiscard]] bool contains(const std::string& symbol) const override { return m_base_composition->contains(symbol); }; + [[nodiscard]] size_t size() const noexcept override { return m_base_composition->size(); }; + [[nodiscard]] std::set getRegisteredSymbols() const noexcept override { return m_base_composition->getRegisteredSymbols(); }; + [[nodiscard]] const std::set &getRegisteredSpecies() const noexcept override { return m_base_composition->getRegisteredSpecies(); }; + [[nodiscard]] std::unordered_map getMassFraction() const noexcept override { return m_base_composition->getMassFraction(); }; + [[nodiscard]] std::unordered_map getNumberFraction() const noexcept override { return m_base_composition->getNumberFraction(); }; + [[nodiscard]] double getMassFraction(const std::string& symbol) const override { return m_base_composition->getMassFraction(symbol); }; + [[nodiscard]] double getMassFraction(const atomic::Species& species) const override { return m_base_composition->getMassFraction(species); }; + [[nodiscard]] double getNumberFraction(const std::string& symbol) const override { return m_base_composition->getNumberFraction(symbol); }; + [[nodiscard]] double getNumberFraction(const atomic::Species& species) const override { return m_base_composition->getNumberFraction(species); }; + [[nodiscard]] double getMolarAbundance(const std::string& symbol) const override { return m_base_composition->getMolarAbundance(symbol); }; + [[nodiscard]] double getMolarAbundance(const atomic::Species& species) const override { return m_base_composition->getMolarAbundance(species); }; + [[nodiscard]] double getMeanParticleMass() const noexcept override { return m_base_composition->getMeanParticleMass(); }; + [[nodiscard]] double getElectronAbundance() const noexcept override { return m_base_composition->getElectronAbundance(); }; + [[nodiscard]] std::vector getMassFractionVector() const noexcept override { return m_base_composition->getMassFractionVector(); }; + [[nodiscard]] std::vector getNumberFractionVector() const noexcept override { return m_base_composition->getNumberFractionVector(); }; + [[nodiscard]] std::vector getMolarAbundanceVector() const noexcept override { return m_base_composition->getMolarAbundanceVector(); }; + [[nodiscard]] size_t getSpeciesIndex(const std::string& symbol) const override { return m_base_composition->getSpeciesIndex(symbol); }; + [[nodiscard]] size_t getSpeciesIndex(const atomic::Species& species) const override { return m_base_composition->getSpeciesIndex(species); }; + [[nodiscard]] atomic::Species getSpeciesAtIndex(const size_t index) const override { return m_base_composition->getSpeciesAtIndex(index); } + + [[nodiscard]] std::map::iterator begin() override { return m_base_composition->begin(); }; + [[nodiscard]] std::map::iterator end() override { return m_base_composition->end(); }; + + [[nodiscard]] std::map::const_iterator begin() const override { return std::as_const(*m_base_composition).begin(); }; + [[nodiscard]] std::map::const_iterator end() const override { return std::as_const(*m_base_composition).end(); }; + protected: + std::unique_ptr m_base_composition; + }; +} \ No newline at end of file diff --git a/src/composition/include/fourdst/composition/decorators/composition_masked.h b/src/composition/include/fourdst/composition/decorators/composition_masked.h new file mode 100644 index 0000000..d9254ac --- /dev/null +++ b/src/composition/include/fourdst/composition/decorators/composition_masked.h @@ -0,0 +1,65 @@ +#pragma once + +#include "fourdst/composition/decorators/composition_decorator_abstract.h" +#include "fourdst/composition/exceptions/exceptions_composition.h" +#include "fourdst/atomic/atomicSpecies.h" + +namespace fourdst::composition { + class MaskedComposition final : public CompositionDecorator { + public: + MaskedComposition( + const CompositionAbstract& baseComposition, + const std::set& activeSpecies + ); + + [[nodiscard]] bool contains(const atomic::Species &species) const noexcept override; + + [[nodiscard]] bool contains(const std::string &symbol) const override; + + [[nodiscard]] const std::set& getRegisteredSpecies() const noexcept override; + + [[nodiscard]] std::set getRegisteredSymbols() const noexcept override; + + [[nodiscard]] size_t size() const noexcept override; + + [[nodiscard]] std::unordered_map getMassFraction() const noexcept override; + + [[nodiscard]] std::unordered_map getNumberFraction() const noexcept override; + + [[nodiscard]] double getMassFraction(const std::string &symbol) const override; + [[nodiscard]] double getMassFraction(const atomic::Species &species) const override; + [[nodiscard]] double getNumberFraction(const std::string &symbol) const override; + [[nodiscard]] double getNumberFraction(const atomic::Species &species) const override; + [[nodiscard]] double getMolarAbundance(const std::string &symbol) const override; + [[nodiscard]] double getMolarAbundance(const atomic::Species &species) const override; + [[nodiscard]] double getMeanParticleMass() const noexcept override; + + [[nodiscard]] double getElectronAbundance() const noexcept override; + + [[nodiscard]] std::vector getMassFractionVector() const noexcept override; + + [[nodiscard]] std::vector getNumberFractionVector() const noexcept override; + + [[nodiscard]] std::vector getMolarAbundanceVector() const noexcept override; + + [[nodiscard]] size_t getSpeciesIndex(const std::string &symbol) const override; + + [[nodiscard]] size_t getSpeciesIndex(const atomic::Species &species) const override; + + [[nodiscard]] atomic::Species getSpeciesAtIndex(size_t index) const override; + + [[nodiscard]] std::unique_ptr clone() const override; + + [[nodiscard]] std::map::iterator begin() override; + + [[nodiscard]] std::map::iterator end() override; + + [[nodiscard]] std::map::const_iterator begin() const override; + + [[nodiscard]] std::map::const_iterator end() const override; + private: + std::set m_activeSpecies; + std::map m_masked_composition; + }; + +} \ No newline at end of file diff --git a/src/composition/lib/decorators/composition_masked.cpp b/src/composition/lib/decorators/composition_masked.cpp new file mode 100644 index 0000000..91d0f2b --- /dev/null +++ b/src/composition/lib/decorators/composition_masked.cpp @@ -0,0 +1,216 @@ +#include "fourdst/composition/decorators/composition_masked.h" + +#include "fourdst/atomic/species.h" + +namespace fourdst::composition { +MaskedComposition::MaskedComposition( + const CompositionAbstract& baseComposition, + const std::set& activeSpecies + ) : + CompositionDecorator(baseComposition.clone()), + m_activeSpecies(activeSpecies) { + for (const auto& species : m_activeSpecies) { + if (CompositionDecorator::contains(species)) { + m_masked_composition.emplace(species, CompositionDecorator::getMolarAbundance(species)); + } else { + m_masked_composition.emplace(species, 0.0); + } + } + } + + bool MaskedComposition::contains(const atomic::Species &species) const noexcept{ + if (m_activeSpecies.contains(species)) { + return true; + } + return false; + } + + bool MaskedComposition::contains(const std::string &symbol) const { + if (!atomic::species.contains(symbol)) { + throw exceptions::UnknownSymbolError("Cannot find species '" + symbol + "' in base composition"); + } + const atomic::Species& species = atomic::species.at(symbol); + if (m_activeSpecies.contains(species)) { + return true; + } + + return false; + } + + const std::set& MaskedComposition::getRegisteredSpecies() const noexcept { + return m_activeSpecies; + } + + std::set MaskedComposition::getRegisteredSymbols() const noexcept { + std::set symbols; + for (const auto& species : m_activeSpecies) { + symbols.insert(std::string(species.name())); + } + return symbols; + } + + size_t MaskedComposition::size() const noexcept { + return m_activeSpecies.size(); + } + + std::unordered_map MaskedComposition::getMassFraction() const noexcept { + std::unordered_map massFractions; + for (const auto& species : m_activeSpecies) { + if (CompositionDecorator::contains(species)) { + massFractions[species] = CompositionDecorator::getMassFraction(species); + } else { + massFractions[species] = 0.0; + } + } + return massFractions; + } + + std::unordered_map MaskedComposition::getNumberFraction() const noexcept { + std::unordered_map numberFractions; + for (const auto& species : m_activeSpecies) { + if (CompositionDecorator::contains(species)) { + numberFractions[species] = CompositionDecorator::getNumberFraction(species); + } else { + numberFractions[species] = 0.0; + } + } + return numberFractions; + } + + double MaskedComposition::getMassFraction(const std::string &symbol) const { + if (!contains(symbol)) { + throw exceptions::UnregisteredSymbolError("Species '" + symbol + "' is not part of the active species in the MaskedComposition."); + } + if (CompositionDecorator::contains(symbol)) { + return CompositionDecorator::getMassFraction(symbol); + } return 0.0; + } + double MaskedComposition::getMassFraction(const atomic::Species &species) const { + if (!contains(species)) { + throw exceptions::UnregisteredSymbolError("Species '" + std::string(species.name()) + "' is not part of the active species in the MaskedComposition."); + } + if (CompositionDecorator::contains(species)) { + return CompositionDecorator::getMassFraction(species); + } return 0.0; + } + double MaskedComposition::getNumberFraction(const std::string &symbol) const { + if (!contains(symbol)) { + throw exceptions::UnregisteredSymbolError("Species '" + symbol + "' is not part of the active species in the MaskedComposition."); + } + if (CompositionDecorator::contains(symbol)) { + return CompositionDecorator::getNumberFraction(symbol); + } return 0.0; + } + double MaskedComposition::getNumberFraction(const atomic::Species &species) const { + if (!contains(species)) { + throw exceptions::UnregisteredSymbolError("Species '" + std::string(species.name()) + "' is not part of the active species in the MaskedComposition."); + } + if (CompositionDecorator::contains(species)) { + return CompositionDecorator::getNumberFraction(species); + } return 0.0; + } + double MaskedComposition::getMolarAbundance(const std::string &symbol) const { + if (!contains(symbol)) { + throw exceptions::UnregisteredSymbolError("Species '" + symbol + "' is not part of the active species in the MaskedComposition."); + } + if (CompositionDecorator::contains(symbol)) { + return CompositionDecorator::getMolarAbundance(symbol); + } return 0.0; + } + double MaskedComposition::getMolarAbundance(const atomic::Species &species) const { + if (!contains(species)) { + throw exceptions::UnregisteredSymbolError("Species '" + std::string(species.name()) + "' is not part of the active species in the MaskedComposition."); + } + if (CompositionDecorator::contains(species)) { + return CompositionDecorator::getMolarAbundance(species); + } return 0.0; + } + double MaskedComposition::getMeanParticleMass() const noexcept { + double meanParticleMass = 0.0; + for (const auto& species : m_activeSpecies) { + if (CompositionDecorator::contains(species)) { + const double numberFraction = CompositionDecorator::getNumberFraction(species); + const double atomicMass = species.mass(); + meanParticleMass += numberFraction * atomicMass; + } + } + return meanParticleMass; + } + + double MaskedComposition::getElectronAbundance() const noexcept { + double Ye = 0.0; + for (const auto& species : m_activeSpecies) { + if (CompositionDecorator::contains(species)) { + Ye += CompositionDecorator::getMolarAbundance(species) * species.z(); + } + } + return Ye; + } + + std::vector MaskedComposition::getMassFractionVector() const noexcept { + std::vector massFractions; + massFractions.reserve(m_activeSpecies.size()); + for (const auto& species : m_activeSpecies) { + massFractions.push_back(getMassFraction(species)); + } + return massFractions; + } + + std::vector MaskedComposition::getNumberFractionVector() const noexcept { + std::vector numberFractions; + numberFractions.reserve(m_activeSpecies.size()); + for (const auto& species : m_activeSpecies) { + numberFractions.push_back(getNumberFraction(species)); + } + return numberFractions; + } + + std::vector MaskedComposition::getMolarAbundanceVector() const noexcept { + std::vector molarAbundances; + molarAbundances.reserve(m_activeSpecies.size()); + for (const auto& species : m_activeSpecies) { + molarAbundances.push_back(getMolarAbundance(species)); + } + return molarAbundances; + } + + size_t MaskedComposition::getSpeciesIndex(const std::string &symbol) const { + if (!contains(symbol)) { + throw exceptions::UnregisteredSymbolError("Species '" + symbol + "' is not part of the active species in the MaskedComposition."); + } + return std::distance(m_activeSpecies.begin(), m_activeSpecies.find(atomic::species.at(symbol))); + } + + size_t MaskedComposition::getSpeciesIndex(const atomic::Species &species) const { + return std::distance(m_activeSpecies.begin(), m_activeSpecies.find(species)); + } + + atomic::Species MaskedComposition::getSpeciesAtIndex(const size_t index) const { + if (index >= m_activeSpecies.size()) { + throw std::out_of_range("Index " + std::to_string(index) + " is out of bounds for active species of size " + std::to_string(m_activeSpecies.size()) + "."); + } + auto it = m_activeSpecies.begin(); + std::advance(it, index); + return *it; + } + + std::unique_ptr MaskedComposition::clone() const { + return std::make_unique(*m_base_composition, m_activeSpecies); + } + + std::map::iterator MaskedComposition::begin() { + return m_masked_composition.begin(); + } + + std::map::iterator MaskedComposition::end() { + return m_masked_composition.end(); + } + + std::map::const_iterator MaskedComposition::begin() const { + return m_masked_composition.cbegin(); + } + + std::map::const_iterator MaskedComposition::end() const { + return m_masked_composition.cend(); + } +}; diff --git a/src/composition/meson.build b/src/composition/meson.build index 8f35816..fc32ac4 100644 --- a/src/composition/meson.build +++ b/src/composition/meson.build @@ -22,6 +22,7 @@ message('✅ libcomposition species_weight dependency declared') composition_sources = files( 'lib/composition.cpp', 'lib/utils.cpp', + 'lib/decorators/composition_masked.cpp', ) diff --git a/tests/composition/compositionTest.cpp b/tests/composition/compositionTest.cpp index 09016e3..3637610 100644 --- a/tests/composition/compositionTest.cpp +++ b/tests/composition/compositionTest.cpp @@ -8,7 +8,7 @@ #include "fourdst/composition/composition.h" #include "fourdst/composition/exceptions/exceptions_composition.h" #include "fourdst/composition/utils.h" -#include "fourdst/composition/composition_abstract.h" +#include "fourdst/composition/decorators/composition_masked.h" #include "fourdst/config/config.h" @@ -236,41 +236,18 @@ TEST_F(compositionTest, buildFromMassFractions) { } - - - -/** - * @brief Tests inheritance from CompositionAbstract and overriding a getter. - * @details This test defines a derived class that overrides getMolarAbundance, - * and verifies that the override works and other getters are inherited. - * @par What this test proves: - * - Derived classes can override getters. - * - All CompositionAbstract children have the standard getter interface. - */ -TEST_F(compositionTest, abstractBase) { - class UnrestrictedComposition : public fourdst::composition::CompositionDecorator { - public: - UnrestrictedComposition(std::unique_ptr base, const fourdst::atomic::Species& species): - CompositionDecorator(std::move(base)), - m_species(species) - {} - - double getMolarAbundance(const fourdst::atomic::Species &species) const override { - if (species == m_species) { - return 1.0; - } - return CompositionDecorator::getMolarAbundance(species); - } - private: - fourdst::atomic::Species m_species; - }; - +TEST_F(compositionTest, decorators) { fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.registerSymbol("O-16"); comp.setMolarAbundance("H-1", 0.6); comp.setMolarAbundance("He-4", 0.6); + const fourdst::composition::MaskedComposition mComp(comp, {fourdst::atomic::H_1, fourdst::atomic::He_4}); + + ASSERT_DOUBLE_EQ(mComp.getMolarAbundance(fourdst::atomic::H_1), 0.6); + ASSERT_DOUBLE_EQ(mComp.getMolarAbundance("He-4"), 0.6); + ASSERT_FALSE(mComp.contains("O-16")); + + comp.setMolarAbundance("H-1", 1.0); + ASSERT_NE(mComp.getMolarAbundance(fourdst::atomic::H_1), 1.0); - const UnrestrictedComposition uComp(std::make_unique(comp), fourdst::atomic::H_1); - ASSERT_DOUBLE_EQ(uComp.getMolarAbundance(fourdst::atomic::H_1), 1.0); - ASSERT_DOUBLE_EQ(uComp.getMassFraction("He-4"), comp.getMassFraction("He-4")); }