feat(Composition): added getMolarAbundance method

This commit is contained in:
2025-06-25 08:26:50 -04:00
parent d740fab76c
commit 5990fa62a7
4 changed files with 74 additions and 41 deletions

View File

@@ -20,7 +20,6 @@
// *********************************************************************** */
#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <set>
@@ -85,7 +84,7 @@ namespace fourdst::composition {
* CompositionEntry entry("H", true);
* @endcode
*/
CompositionEntry(const std::string& symbol, bool massFracMode=true);
explicit CompositionEntry(const std::string& symbol, bool massFracMode=true);
/**
* @brief Copy constructor.
@@ -103,51 +102,51 @@ namespace fourdst::composition {
* @brief Gets the chemical symbol of the species.
* @return The chemical symbol of the species.
*/
std::string symbol() const;
[[nodiscard]] std::string symbol() const;
/**
* @brief Gets the mass fraction of the species.
* @return The mass fraction of the species.
*/
double mass_fraction() const;
[[nodiscard]] double mass_fraction() const;
/**
* @brief Gets the mass fraction of the species given the mean molar mass.
* @param meanMolarMass The mean molar mass.
* @return The mass fraction of the species.
*/
double mass_fraction(double meanMolarMass) const;
[[nodiscard]] double mass_fraction(double meanMolarMass) const;
/**
* @brief Gets the number fraction of the species.
* @return The number fraction of the species.
*/
double number_fraction() const;
[[nodiscard]] double number_fraction() const;
/**
* @brief Gets the number fraction of the species given the total moles.
* @param totalMoles The total moles.
* @return The number fraction of the species.
*/
double number_fraction(double totalMoles) const;
[[nodiscard]] double number_fraction(double totalMoles) const;
/**
* @brief Gets the relative abundance of the species.
* @return The relative abundance of the species.
*/
double rel_abundance() const;
[[nodiscard]] double rel_abundance() const;
/**
* @brief Gets the isotope of the species.
* @return The isotope of the species.
*/
fourdst::atomic::Species isotope() const;
[[nodiscard]] atomic::Species isotope() const;
/**
* @brief Gets the mode of the composition entry.
* @return True if mass fraction mode, false if number fraction mode.
*/
bool getMassFracMode() const;
[[nodiscard]] bool getMassFracMode() const;
/**
* @brief Sets the mass fraction of the species.
@@ -191,10 +190,10 @@ namespace fourdst::composition {
* any part of 4DSSE. There are a few rules when using this class.
* - Only species in the atomicSpecies.h database can be used. There are 1000s (All species from AME2020) in there so it should not be a problem.
* - Before a mass fraction can be set with a particular instance of Composition, the symbol must be registered. (i.e. register He-3 before setting its mass fraction)
* - Before any composition information can be retrived (e.g. getComposition), the composition must be finalized (call to .finalize()). This checks if the total mass fraction sums to approximatly 1 (within 1 part in 10^8)
* - Any changes made to the composition after finalization will "unfinalize" the composition. This means that the composition must be finalized again before any information can be retrived.
* - Before any composition information can be retrieved (e.g. getComposition), the composition must be finalized (call to .finalize()). This checks if the total mass fraction sums to approximately 1 (within 1 part in 10^8)
* - Any changes made to the composition after finalization will "un-finalize" the composition. This means that the composition must be finalized again before any information can be retrieved.
* - The mass fraction of any individual species must be no more than 1 and no less than 0.
* - The only exception to the finalize rule is if the compositon was constructed with symbols and mass fractions at instantiation time. In this case, the composition is automatically finalized.
* - The only exception to the finalize rule is if the composition was constructed with symbols and mass fractions at instantiation time. In this case, the composition is automatically finalized.
* however, this means that the composition passed to the constructor must be valid.
*
* *Example Usage:* Constructing a finalized composition with symbols and mass fractions:
@@ -236,14 +235,14 @@ namespace fourdst::composition {
/**
* @brief Checks if the given mass fractions are valid.
* @param mass_fractions The mass fractions to check.
* @param fractions The mass fractions to check.
* @return True if the mass fractions are valid, false otherwise.
*/
bool isValidComposition(const std::vector<double>& fractions) const;
[[nodiscard]] bool isValidComposition(const std::vector<double>& fractions) const;
/**
* @brief Validates the given mass fractions.
* @param mass_fractions The mass fractions to validate.
* @param fractions The mass fractions to validate.
* @throws std::invalid_argument if the mass fractions are invalid.
*/
void validateComposition(const std::vector<double>& fractions) const;
@@ -402,9 +401,9 @@ namespace fourdst::composition {
/**
* @brief Mix two compositions together with a given fraction.
* @param other The other composition to mix with.
* @param fraction The fraction of the other composition to mix with. This is the fraction of the other composition wrt. to the current. i.e. fraction=1 would mean that 50% of the new composition is from the other and 50% from the current).
* @param fraction The fraction of the other composition to mix with. This is the fraction of the other composition wrt. to the current. i.e. fraction=1 would mean that 50% of the new composition is from the other and 50% from the current.
*/
Composition mix(const Composition& other, double fraction) const;
[[nodiscard]] Composition mix(const Composition& other, double fraction) const;
/**
* @brief Gets the mass fractions of all compositions.
@@ -432,6 +431,13 @@ namespace fourdst::composition {
*/
[[nodiscard]] std::unordered_map<std::string, double> getNumberFraction() const;
/**
* @brief Gets the molar abundance for a given symbol.
* @param symbol The symbol to get the molar abundance for.
* @return The molar abundance for the given symbol.
*/
[[nodiscard]] double getMolarAbundance(const std::string& symbol) const;
/**
* @brief Gets the composition entry and global composition for a given symbol.
* @param symbol The symbol to get the composition for.
@@ -463,16 +469,16 @@ namespace fourdst::composition {
* @param method The method to use for the subset (default is "norm").
* @return A Composition object containing the subset.
*/
Composition subset(const std::vector<std::string>& symbols, std::string method="norm") const;
[[nodiscard]] Composition subset(const std::vector<std::string>& symbols, const std::string& method="norm") const;
/**
* @brief Check if a symbol is registered.
* @param symbol The symbol to check.
* @return True if the symbol is registered, false otherwise.
*/
bool hasSymbol(const std::string& symbol) const;
[[nodiscard]] bool hasSymbol(const std::string& symbol) const;
bool contains(const fourdst::atomic::Species& isotope) const;
[[nodiscard]] bool contains(const fourdst::atomic::Species& isotope) const;
/**
* @brief Sets the composition mode.

View File

@@ -56,7 +56,7 @@ namespace fourdst::composition {
if (m_initialized) {
throw std::runtime_error("Composition entry is already initialized.");
}
if (fourdst::atomic::species.count(symbol) == 0) {
if (!fourdst::atomic::species.contains(symbol)) {
throw std::runtime_error("Invalid symbol.");
}
m_symbol = symbol;
@@ -207,7 +207,7 @@ namespace fourdst::composition {
}
// If no symbols have been registered allow mode to be set
if (m_registeredSymbols.size() == 0) {
if (m_registeredSymbols.empty()) {
m_massFracMode = massFracMode;
} else {
if (m_massFracMode != massFracMode) {
@@ -216,13 +216,13 @@ namespace fourdst::composition {
}
}
if (m_registeredSymbols.find(symbol) != m_registeredSymbols.end()) {
if (m_registeredSymbols.contains(symbol)) {
LOG_WARNING(m_logger, "Symbol {} is already registered.", symbol);
return;
}
m_registeredSymbols.insert(symbol);
CompositionEntry entry(symbol, m_massFracMode);
const CompositionEntry entry(symbol, m_massFracMode);
m_compositions[symbol] = entry;
LOG_INFO(m_logger, "Registered symbol: {}", symbol);
}
@@ -299,7 +299,7 @@ namespace fourdst::composition {
}
double Composition::setNumberFraction(const std::string& symbol, const double& number_fraction) {
if (m_registeredSymbols.find(symbol) == m_registeredSymbols.end()) {
if (!m_registeredSymbols.contains(symbol)) {
LOG_ERROR(m_logger, "Symbol {} is not registered.", symbol);
throw std::runtime_error("Symbol is not registered.");
}
@@ -351,7 +351,7 @@ namespace fourdst::composition {
bool Composition::finalizeMassFracMode(bool norm) {
std::vector<double> mass_fractions;
mass_fractions.reserve(m_compositions.size());
for (const auto& [_, entry] : m_compositions) {
for (const auto &entry: m_compositions | std::views::values) {
mass_fractions.push_back(entry.mass_fraction());
}
if (norm) {
@@ -359,8 +359,8 @@ namespace fourdst::composition {
for (const auto& mass_fraction : mass_fractions) {
sum += mass_fraction;
}
for (int i = 0; i < static_cast<int>(mass_fractions.size()); ++i) {
mass_fractions[i] /= sum;
for (double & mass_fraction : mass_fractions) {
mass_fraction /= sum;
}
for (auto& [symbol, entry] : m_compositions) {
setMassFraction(symbol, entry.mass_fraction() / sum);
@@ -368,16 +368,16 @@ namespace fourdst::composition {
}
try {
validateComposition(mass_fractions);
} catch (const std::runtime_error& e) {
} catch ([[maybe_unused]] const std::runtime_error& e) {
double massSum = 0.0;
for (const auto& [_, entry] : m_compositions) {
for (const auto &entry: m_compositions | std::views::values) {
massSum += entry.mass_fraction();
}
LOG_ERROR(m_logger, "Composition is invalid (Total mass {}).", massSum);
m_finalized = false;
return false;
}
for (const auto& [_, entry] : m_compositions) {
for (const auto &entry: m_compositions | std::views::values) {
m_specificNumberDensity += entry.rel_abundance();
}
m_meanParticleMass = 1.0/m_specificNumberDensity;
@@ -387,7 +387,7 @@ namespace fourdst::composition {
bool Composition::finalizeNumberFracMode(bool norm) {
std::vector<double> number_fractions;
number_fractions.reserve(m_compositions.size());
for (const auto& [_, entry] : m_compositions) {
for (const auto &entry: m_compositions | std::views::values) {
number_fractions.push_back(entry.number_fraction());
}
if (norm) {
@@ -401,16 +401,16 @@ namespace fourdst::composition {
}
try {
validateComposition(number_fractions);
} catch (const std::runtime_error& e) {
} catch ([[maybe_unused]] const std::runtime_error& e) {
double numberSum = 0.0;
for (const auto& [_, entry] : m_compositions) {
for (const auto &entry: m_compositions | std::views::values) {
numberSum += entry.number_fraction();
}
LOG_ERROR(m_logger, "Composition is invalid (Total number {}).", numberSum);
m_finalized = false;
return false;
}
for (const auto& [_, entry] : m_compositions) {
for (const auto &entry: m_compositions | std::views::values) {
m_meanParticleMass += entry.rel_abundance();
}
m_specificNumberDensity = 1.0/m_meanParticleMass;
@@ -453,7 +453,7 @@ namespace fourdst::composition {
}
if (!m_compositions.contains(symbol)) {
LOG_ERROR(m_logger, "Symbol {} is not in the composition.", symbol);
std::string currentSymbols = "";
std::string currentSymbols;
int count = 0;
for (const auto& sym : m_compositions | std::views::keys) {
currentSymbols += sym;
@@ -506,6 +506,19 @@ namespace fourdst::composition {
return number_fractions;
}
double Composition::getMolarAbundance(const std::string &symbol) const {
if (!m_finalized) {
LOG_ERROR(m_logger, "Composition has not been finalized.");
throw std::runtime_error("Composition has not been finalized (Consider running .finalize()).");
}
if (!m_compositions.contains(symbol)) {
LOG_ERROR(m_logger, "Symbol {} is not in the composition.", symbol);
throw std::runtime_error("Symbol is not in the composition.");
}
return getMassFraction(symbol) / m_compositions.at(symbol).isotope().mass();
}
std::pair<CompositionEntry, GlobalComposition> Composition::getComposition(const std::string& symbol) const {
if (!m_finalized) {
LOG_ERROR(m_logger, "Composition has not been finalized.");
@@ -551,7 +564,7 @@ namespace fourdst::composition {
return mean_A;
}
Composition Composition::subset(const std::vector<std::string>& symbols, std::string method) const {
Composition Composition::subset(const std::vector<std::string>& symbols, const std::string& method) const {
const std::array<std::string, 2> methods = {"norm", "none"};
if (std::ranges::find(methods, method) == methods.end()) {
@@ -649,7 +662,7 @@ namespace fourdst::composition {
}
bool Composition::hasSymbol(const std::string& symbol) const {
return m_compositions.count(symbol) > 0;
return m_compositions.contains(symbol);
}
bool Composition::contains(const fourdst::atomic::Species &isotope) const {
@@ -686,7 +699,7 @@ namespace fourdst::composition {
std::ostream& operator<<(std::ostream& os, const Composition& composition) {
os << "Composition(finalized: " << (composition.m_finalized ? "true" : "false") << ", " ;
int count = 0;
for (const auto& [symbol, entry] : composition.m_compositions) {
for (const auto &entry: composition.m_compositions | std::views::values) {
os << entry;
if (count < composition.m_compositions.size() - 1) {
os << ", ";