diff --git a/meson.build b/meson.build index b16b3e1..672da4b 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.1.0', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0') +project('libcomposition', 'cpp', version: 'v2.2.0', 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.h b/src/composition/include/fourdst/composition/composition.h index 98f8e9e..5e42f66 100644 --- a/src/composition/include/fourdst/composition/composition.h +++ b/src/composition/include/fourdst/composition/composition.h @@ -25,6 +25,7 @@ #include #include +#include #include "fourdst/config/config.h" #include "fourdst/logging/logging.h" @@ -218,6 +219,9 @@ namespace fourdst::composition { */ explicit Composition(const std::set& species); + explicit Composition(const std::unordered_set& symbols); + explicit Composition(const std::unordered_set& species); + /** * @brief Constructs a Composition from symbols and their corresponding molar abundances. * @param symbols The symbols to register. @@ -268,6 +272,13 @@ namespace fourdst::composition { */ Composition(const std::set& symbols, const std::vector& molarAbundances); + explicit Composition(const std::unordered_map& symbolMolarAbundances); + explicit Composition(const std::map& symbolMolarAbundances); + + explicit Composition(const std::unordered_map& speciesMolarAbundances); + explicit Composition(const std::map& speciesMolarAbundances); + + /** * @brief Constructs a Composition from another Composition. * @param composition The Composition to copy. diff --git a/src/composition/include/fourdst/composition/utils.h b/src/composition/include/fourdst/composition/utils.h index 9925e40..6c5707c 100644 --- a/src/composition/include/fourdst/composition/utils.h +++ b/src/composition/include/fourdst/composition/utils.h @@ -47,4 +47,44 @@ namespace fourdst::composition { const std::set& species, const std::vector& massFractions ); + + /** + * @brief Build a Composition object from a map of species to mass fractions. + * @param massFractionsMap The map of species to their corresponding mass fractions. + * @return A Composition object constructed from the provided species and mass fractions. + * @throws exceptions::InvalidCompositionError if the provided mass fractions do not sum to within one part in 10^10 of 1.0. + */ + Composition buildCompositionFromMassFractions( + const std::unordered_map& massFractionsMap + ); + + /** + * @brief Build a Composition object from a map of species to mass fractions. + * @param massFractions The map of species to their corresponding mass fractions. + * @return A Composition object constructed from the provided species and mass fractions. + * @throws exceptions::InvalidCompositionError if the provided mass fractions do not sum to within one part in 10^10 of 1.0. + */ + Composition buildCompositionFromMassFractions( + const std::unordered_map& massFractions + ); + + /** + * @brief Build a Composition object from a map of species to mass fractions. + * @param massFractions The map of species to their corresponding mass fractions. + * @return A Composition object constructed from the provided species and mass fractions. + * @throws exceptions::InvalidCompositionError if the provided mass fractions do not sum to within one part in 10^10 of 1.0. + */ + Composition buildCompositionFromMassFractions( + std::map massFractions + ); + + /** + * @brief Build a Composition object from a map of species to mass fractions. + * @param massFractions The map of species to their corresponding mass fractions. + * @return A Composition object constructed from the provided species and mass fractions. + * @throws exceptions::InvalidCompositionError if the provided mass fractions do not sum to within one part in 10^10 of 1.0. + */ + Composition buildCompositionFromMassFractions( + std::map massFractions + ); } \ No newline at end of file diff --git a/src/composition/lib/composition.cpp b/src/composition/lib/composition.cpp index 6646d59..0d73ade 100644 --- a/src/composition/lib/composition.cpp +++ b/src/composition/lib/composition.cpp @@ -113,6 +113,18 @@ namespace fourdst::composition { } } + Composition::Composition(const std::unordered_set &symbols) { + for (const auto& symbol : symbols) { + registerSymbol(symbol); + } + } + + Composition::Composition(const std::unordered_set &species) { + for (const auto& s : species) { + registerSpecies(s); + } + } + Composition::Composition( const std::vector& symbols, const std::vector& molarAbundances @@ -158,6 +170,34 @@ namespace fourdst::composition { } } + Composition::Composition(const std::unordered_map &symbolMolarAbundances) { + for (const auto& [symbol, y] : symbolMolarAbundances) { + registerSymbol(symbol); + setMolarAbundance(symbol, y); + } + } + + Composition::Composition(const std::map &symbolMolarAbundances) { + for (const auto& [symbol, y] : symbolMolarAbundances) { + registerSymbol(symbol); + setMolarAbundance(symbol, y); + } + } + + Composition::Composition(const std::unordered_map &speciesMolarAbundances) { + for (const auto& [species, y] : speciesMolarAbundances) { + registerSpecies(species); + setMolarAbundance(species, y); + } + } + + Composition::Composition(const std::map &speciesMolarAbundances) { + for (const auto& [species, y] : speciesMolarAbundances) { + registerSpecies(species); + setMolarAbundance(species, y); + } + } + Composition::Composition( const Composition &composition ) { diff --git a/src/composition/lib/utils.cpp b/src/composition/lib/utils.cpp index 291d804..16b86c7 100644 --- a/src/composition/lib/utils.cpp +++ b/src/composition/lib/utils.cpp @@ -68,7 +68,17 @@ namespace fourdst::composition { } Composition buildCompositionFromMassFractions(const std::vector &species, const std::vector &massFractions) { - return buildCompositionFromMassFractions(std::set(species.begin(), species.end()), massFractions); + std::set speciesSet(species.begin(), species.end()); + std::vector sortedMassFractions; + + sortedMassFractions.resize(massFractions.size()); + for (const auto& [s, xi] : std::views::zip(species, massFractions)) { + const size_t index = std::distance(speciesSet.begin(), speciesSet.find(s)); + assert (index < sortedMassFractions.size()); + sortedMassFractions[index] = xi; + } + + return buildCompositionFromMassFractions(speciesSet, sortedMassFractions); } Composition buildCompositionFromMassFractions(const std::vector &symbols, const std::vector &massFractions) { @@ -80,6 +90,107 @@ namespace fourdst::composition { } species.insert(result.value()); } + + std::vector sortedMassFractions(massFractions.size()); + for (const auto& [symbol, xi] : std::views::zip(symbols, massFractions)) { + auto result = getSpecies(symbol); + if (!result) { + throw_unknown_symbol(symbol); + } + const size_t index = std::distance(species.begin(), species.find(result.value())); + assert (index < sortedMassFractions.size()); + sortedMassFractions[index] = xi; + } + return buildCompositionFromMassFractions(species, sortedMassFractions); + } + + Composition buildCompositionFromMassFractions(const std::unordered_map& massFractionsMap) { + std::set species; + std::vector massFractions; + + massFractions.reserve(massFractionsMap.size()); + + for (const auto &sp: massFractionsMap | std::views::keys) { + species.insert(sp); + } + + massFractions.resize(massFractionsMap.size()); + for (const auto& [sp, xi] : massFractionsMap) { + const size_t index = std::distance(species.begin(), species.find(sp)); + assert (index < massFractions.size()); + massFractions[index] = xi; + } + return buildCompositionFromMassFractions(species, massFractions); } + + Composition buildCompositionFromMassFractions(std::map massFractions) { + std::set species; + std::vector massFractionVector; + + massFractionVector.reserve(massFractions.size()); + + for (const auto& [sp, xi] : massFractions) { + species.insert(sp); + massFractionVector.push_back(xi); + } + + return buildCompositionFromMassFractions(species, massFractionVector); + } + + Composition buildCompositionFromMassFractions(std::map massFractions) { + std::set species; + std::vector massFractionVector; + + + for (const auto &symbol: massFractions | std::views::keys) { + auto result = getSpecies(symbol); + if (!result) { + throw_unknown_symbol(symbol); + } + species.insert(result.value()); + } + + massFractionVector.resize(massFractions.size()); + + for (const auto& [symbol, xi] : massFractions) { + auto result = getSpecies(symbol); + if (!result) { + throw_unknown_symbol(symbol); + } + const size_t index = std::distance(species.begin(), species.find(result.value())); + assert (index < massFractionVector.size()); + massFractionVector[index] = xi; + } + + + return buildCompositionFromMassFractions(species, massFractionVector); + } + + Composition buildCompositionFromMassFractions(const std::unordered_map& massFractions) { + std::set species; + std::vector massFractionVector; + + for (const auto &symbol: massFractions | std::views::keys) { + auto result = getSpecies(symbol); + if (!result) { + throw_unknown_symbol(symbol); + } + species.insert(result.value()); + } + + massFractionVector.resize(massFractions.size()); + for (const auto& [sp, xi] : massFractions) { + auto result = getSpecies(sp); + if (!result) { + throw_unknown_symbol(sp); + } + const size_t index = std::distance(species.begin(), species.find(result.value())); + assert (index < massFractionVector.size()); + massFractionVector[index] = xi; + } + + return buildCompositionFromMassFractions(species, massFractionVector); + } + } \ No newline at end of file diff --git a/tests/composition/compositionTest.cpp b/tests/composition/compositionTest.cpp index 2201fbe..791baf6 100644 --- a/tests/composition/compositionTest.cpp +++ b/tests/composition/compositionTest.cpp @@ -221,12 +221,44 @@ TEST_F(compositionTest, meanElectronAbundance) { EXPECT_NEAR(comp.getElectronAbundance(), expectedYe, 1e-12); } -TEST_F(compositionTest, buildFromMassFractions) { +TEST_F(compositionTest, buildFromMassFractionVector) { using fourdst::atomic::Species; using namespace fourdst::atomic; using fourdst::composition::Composition; - const std::vector sVec = {H_1, He_4, C_12}; + const std::vector sVec = {H_1, Mg_24, He_4, C_12}; + const std::vector massFractions = {0.7, 0.01, 0.28, 0.01}; + + const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sVec, massFractions); + + EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); + EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); + EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.01); + EXPECT_DOUBLE_EQ(comp.getMassFraction(Mg_24), 0.01); +} + +TEST_F(compositionTest, buildFromMassFractionVectorString) { + using fourdst::atomic::Species; + using namespace fourdst::atomic; + using fourdst::composition::Composition; + + const std::vector sVec = {"H-1", "Mg-24", "He-4", "C-12"}; + const std::vector massFractions = {0.7, 0.01, 0.28, 0.01}; + + const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sVec, massFractions); + + EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); + EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); + EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.01); + EXPECT_DOUBLE_EQ(comp.getMassFraction(Mg_24), 0.01); +} + +TEST_F(compositionTest, buildFromMassFractionSet) { + using fourdst::atomic::Species; + using namespace fourdst::atomic; + using fourdst::composition::Composition; + + const std::set sVec = {H_1, He_4, C_12}; const std::vector massFractions = {0.7, 0.28, 0.02}; const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sVec, massFractions); @@ -234,7 +266,66 @@ TEST_F(compositionTest, buildFromMassFractions) { EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.02); +} +TEST_F(compositionTest, buildFromMassFractionUnorderedMap) { + using fourdst::atomic::Species; + using namespace fourdst::atomic; + using fourdst::composition::Composition; + + const std::unordered_map sMap = {{H_1, 0.7}, {Mg_24, 0.01}, {He_4, 0.28}, {C_12, 0.01}}; + + const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sMap); + + EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); + EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); + EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.01); + EXPECT_DOUBLE_EQ(comp.getMassFraction(Mg_24), 0.01); +} + +TEST_F(compositionTest, buildFromMassFractionUnorderedMapString) { + using fourdst::atomic::Species; + using namespace fourdst::atomic; + using fourdst::composition::Composition; + + const std::unordered_map sMap = {{"H-1", 0.7}, {"Mg-24", 0.01}, {"He-4", 0.28}, {"C-12", 0.01}}; + + const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sMap); + + EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); + EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); + EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.01); + EXPECT_DOUBLE_EQ(comp.getMassFraction(Mg_24), 0.01); +} + +TEST_F(compositionTest, buildFromMassFractionOrderedMap) { + using fourdst::atomic::Species; + using namespace fourdst::atomic; + using fourdst::composition::Composition; + + const std::map sMap = {{H_1, 0.7}, {Mg_24, 0.01}, {He_4, 0.28}, {C_12, 0.01}}; + + const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sMap); + + EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); + EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); + EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.01); + EXPECT_DOUBLE_EQ(comp.getMassFraction(Mg_24), 0.01); +} + +TEST_F(compositionTest, buildFromMassFractionOrderedMapString) { + using fourdst::atomic::Species; + using namespace fourdst::atomic; + using fourdst::composition::Composition; + + const std::map sMap = {{"H-1", 0.7}, {"Mg-24", 0.01}, {"He-4", 0.28}, {"C-12", 0.01}}; + + const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sMap); + + EXPECT_DOUBLE_EQ(comp.getMassFraction(H_1), 0.7); + EXPECT_DOUBLE_EQ(comp.getMassFraction(He_4), 0.28); + EXPECT_DOUBLE_EQ(comp.getMassFraction(C_12), 0.01); + EXPECT_DOUBLE_EQ(comp.getMassFraction(Mg_24), 0.01); } TEST_F(compositionTest, decorators) {