Merge pull request #7 from tboudreaux/feature/molarAbundance
feat(composition): changed how composition is conmstructed
This commit is contained in:
2
Doxyfile
2
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 = v1.9.1
|
||||
PROJECT_NUMBER = v2.0.0
|
||||
|
||||
# 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
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# *********************************************************************** #
|
||||
project('libcomposition', 'cpp', version: 'v1.9.1', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
|
||||
project('libcomposition', 'cpp', version: 'v2.0.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')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <limits>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace fourdst::atomic {
|
||||
* @param jpi_string The spin-parity string to convert (e.g., "1/2+", "5/2-", "0+").
|
||||
* @return The spin value as a double. Returns `NaN` for invalid or unparsable strings.
|
||||
*/
|
||||
inline double convert_jpi_to_double(const std::string& jpi_string);
|
||||
inline double convert_jpi_to_double(const std::string& jpi_string) noexcept;
|
||||
|
||||
/**
|
||||
* @struct Species
|
||||
@@ -63,7 +63,7 @@ namespace fourdst::atomic {
|
||||
std::string m_decayModes; ///< Decay modes as a string.
|
||||
double m_atomicMass; ///< Atomic mass in atomic mass units (u).
|
||||
double m_atomicMassUnc; ///< Uncertainty in the atomic mass.
|
||||
double m_spin = 0.0; ///< Nuclear spin as a double, derived from m_spinParity.
|
||||
mutable std::optional<double> m_spin = std::nullopt; ///< Nuclear spin as a double, derived from m_spinParity.
|
||||
|
||||
/**
|
||||
* @brief Constructs a Species object with detailed properties.
|
||||
@@ -114,9 +114,7 @@ namespace fourdst::atomic {
|
||||
m_spinParity(spinParity),
|
||||
m_decayModes(decayModes),
|
||||
m_atomicMass(atomicMass),
|
||||
m_atomicMassUnc(atomicMassUnc) {
|
||||
m_spin = convert_jpi_to_double(m_spinParity);
|
||||
};
|
||||
m_atomicMassUnc(atomicMassUnc) {};
|
||||
|
||||
/**
|
||||
* @brief Copy constructor for Species.
|
||||
@@ -138,7 +136,6 @@ namespace fourdst::atomic {
|
||||
m_decayModes = species.m_decayModes;
|
||||
m_atomicMass = species.m_atomicMass;
|
||||
m_atomicMassUnc = species.m_atomicMassUnc;
|
||||
m_spin = convert_jpi_to_double(m_spinParity);
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +256,10 @@ namespace fourdst::atomic {
|
||||
* @return The spin as a double.
|
||||
*/
|
||||
[[nodiscard]] double spin() const {
|
||||
return m_spin;
|
||||
if (!m_spin.has_value()) { // The spin calculation is very expensive, and we almost never need it so we only compute it the first time it is requested
|
||||
m_spin = convert_jpi_to_double(m_spinParity);
|
||||
}
|
||||
return m_spin.value();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +345,7 @@ namespace fourdst::atomic {
|
||||
*
|
||||
* @return The spin value as a `double`. Returns `NaN` for invalid or unparsable strings.
|
||||
*/
|
||||
inline double convert_jpi_to_double(const std::string& jpi_string) {
|
||||
inline double convert_jpi_to_double(const std::string& jpi_string) noexcept {
|
||||
std::string s = jpi_string;
|
||||
|
||||
if (s.empty()) {
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <limits> // Required for std::numeric_limits
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/composition/elements.h"
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
#include "elements.h"
|
||||
|
||||
#include <expected> // For std::expected
|
||||
|
||||
@@ -24,13 +24,12 @@
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#include <utility>
|
||||
#include <optional>
|
||||
|
||||
#include "fourdst/config/config.h"
|
||||
#include "fourdst/logging/logging.h"
|
||||
#include "fourdst/composition/composition_abstract.h"
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
|
||||
namespace fourdst::composition {
|
||||
/**
|
||||
@@ -62,158 +61,6 @@ namespace fourdst::composition {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents global properties of a finalized composition.
|
||||
* @details This struct holds derived quantities that describe the entire composition,
|
||||
* such as mean particle mass. It is typically returned by `Composition` methods
|
||||
* after the composition has been finalized and is intended for internal or advanced use.
|
||||
*/
|
||||
struct GlobalComposition {
|
||||
double specificNumberDensity; ///< The specific number density (moles per unit mass, sum of X_i/M_i), where X_i is mass fraction and M_i is molar mass. Units: mol/g.
|
||||
double meanParticleMass; ///< The mean mass per particle (inverse of specific number density). Units: g/mol.
|
||||
|
||||
// Overload the output stream operator for GlobalComposition
|
||||
friend std::ostream& operator<<(std::ostream& os, const GlobalComposition& comp);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents a single entry (an isotope) within a composition.
|
||||
* @details This struct holds the properties of one component, including its symbol,
|
||||
* the corresponding `atomic::Species` object, and its abundance (either as a mass
|
||||
* fraction or number fraction). It manages the state and conversions for that single entry.
|
||||
*/
|
||||
struct CompositionEntry {
|
||||
std::optional<std::string> m_symbol = std::nullopt; ///< The chemical symbol of the species (e.g., "H-1", "Fe-56").
|
||||
std::optional<atomic::Species> m_isotope = std::nullopt; ///< The `atomic::Species` object containing detailed isotope data.
|
||||
bool m_massFracMode = true; ///< The mode of the composition entry. True if mass fraction, false if number fraction.
|
||||
|
||||
double m_massFraction = 0.0; ///< The mass fraction of the species. Valid only if `m_massFracMode` is true.
|
||||
double m_numberFraction = 0.0; ///< The number fraction (mole fraction) of the species. Valid only if `m_massFracMode` is false.
|
||||
double m_relAbundance = 0.0; ///< The relative abundance, used internally for conversions. For mass fraction mode, this is X_i / A_i; for number fraction mode, it's n_i * A_i.
|
||||
double m_molesPerMass = 0.0;
|
||||
double m_cachedNumberFraction = 0.0; ///< Cached number fraction for conversions when in mass fraction mode.
|
||||
|
||||
|
||||
bool m_initialized = false; ///< True if the composition entry has been initialized with a valid species.
|
||||
|
||||
/**
|
||||
* @brief Default constructor. Initializes a default entry (H-1), but in an uninitialized state.
|
||||
*/
|
||||
CompositionEntry();
|
||||
|
||||
/**
|
||||
* @brief Constructs a CompositionEntry for a given symbol and abundance mode.
|
||||
* @param symbol The chemical symbol of the species (e.g., "He-4").
|
||||
* @param massFracMode True to operate in mass fraction mode, false for number fraction mode.
|
||||
* @throws exceptions::InvalidSpeciesSymbolError if the symbol does not exist in the atomic species database.
|
||||
* @throws exceptions::EntryAlreadyInitializedError if setSpecies is called on an already initialized entry.
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* CompositionEntry entry("H-1", true); // Entry for H-1 in mass fraction mode.
|
||||
* @endcode
|
||||
*/
|
||||
explicit CompositionEntry(const std::string& symbol, bool massFracMode=true);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param entry The CompositionEntry to copy.
|
||||
*/
|
||||
CompositionEntry(const CompositionEntry& entry);
|
||||
|
||||
/**
|
||||
* @brief Sets the species for the composition entry. This can only be done once.
|
||||
* @param symbol The chemical symbol of the species.
|
||||
* @throws exceptions::EntryAlreadyInitializedError if the entry has already been initialized.
|
||||
* @throws exceptions::InvalidSpeciesSymbolError if the symbol is not found in the atomic species database.
|
||||
*/
|
||||
void setSpecies(const std::string& symbol);
|
||||
|
||||
/**
|
||||
* @brief Gets the chemical symbol of the species.
|
||||
* @return The chemical symbol.
|
||||
*/
|
||||
[[nodiscard]] std::string symbol() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the mass fraction of the species.
|
||||
* @pre The entry must be in mass fraction mode.
|
||||
* @return The mass fraction of the species.
|
||||
* @throws exceptions::CompositionModeError if the entry is in number fraction mode.
|
||||
*/
|
||||
[[nodiscard]] double mass_fraction() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the number fraction of the species.
|
||||
* @pre The entry must be in number fraction mode.
|
||||
* @return The number fraction of the species.
|
||||
* @throws exceptions::CompositionModeError if the entry is in mass fraction mode.
|
||||
*/
|
||||
[[nodiscard]] double number_fraction() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the number fraction, converting from mass fraction if necessary.
|
||||
* @param totalMolesPerMass The total moles per unit mass (specific number density) of the entire composition.
|
||||
* @return The number fraction of the species.
|
||||
*/
|
||||
[[nodiscard]] double number_fraction(double totalMolesPerMass) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the relative abundance of the species.
|
||||
* @return The relative abundance.
|
||||
*/
|
||||
[[nodiscard]] double rel_abundance() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the isotope data for the species.
|
||||
* @return A const reference to the `atomic::Species` object.
|
||||
*/
|
||||
[[nodiscard]] atomic::Species isotope() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the mode of the composition entry.
|
||||
* @return True if in mass fraction mode, false if in number fraction mode.
|
||||
*/
|
||||
[[nodiscard]] bool getMassFracMode() const;
|
||||
|
||||
/**
|
||||
* @brief Sets the mass fraction of the species.
|
||||
* @param mass_fraction The mass fraction to set. Must be in [0, 1].
|
||||
* @pre The entry must be in mass fraction mode.
|
||||
* @throws exceptions::CompositionModeError if the entry is in number fraction mode.
|
||||
*/
|
||||
void setMassFraction(double mass_fraction);
|
||||
|
||||
/**
|
||||
* @brief Sets the number fraction of the species.
|
||||
* @param number_fraction The number fraction to set. Must be in [0, 1].
|
||||
* @pre The entry must be in number fraction mode.
|
||||
* @throws exceptions::CompositionModeError if the entry is in mass fraction mode.
|
||||
*/
|
||||
void setNumberFraction(double number_fraction);
|
||||
|
||||
/**
|
||||
* @brief Switches the mode to mass fraction mode.
|
||||
* @param meanMolarMass The mean molar mass of the composition, required for conversion.
|
||||
* @return True if the mode was successfully set, false otherwise.
|
||||
*/
|
||||
bool setMassFracMode(double meanMolarMass);
|
||||
|
||||
/**
|
||||
* @brief Switches the mode to number fraction mode.
|
||||
* @param totalMolesPerMass The total moles per unit mass (specific number density) of the composition.
|
||||
* @return True if the mode was successfully set, false otherwise.
|
||||
*/
|
||||
bool setNumberFracMode(double totalMolesPerMass);
|
||||
|
||||
/**
|
||||
* @brief Overloaded output stream operator for CompositionEntry.
|
||||
* @param os The output stream.
|
||||
* @param entry The CompositionEntry to output.
|
||||
* @return The output stream.
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& os, const CompositionEntry& entry);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Composition
|
||||
* @brief Manages a collection of chemical species and their abundances.
|
||||
@@ -256,7 +103,6 @@ namespace fourdst::composition {
|
||||
class Composition : public CompositionAbstract {
|
||||
private:
|
||||
struct CompositionCache {
|
||||
std::optional<GlobalComposition> globalComp; ///< Cached global composition data.
|
||||
std::optional<CanonicalComposition> canonicalComp; ///< Cached canonical composition data.
|
||||
std::optional<std::vector<double>> massFractions; ///< Cached vector of mass fractions.
|
||||
std::optional<std::vector<double>> numberFractions; ///< Cached vector of number fractions.
|
||||
@@ -266,7 +112,6 @@ namespace fourdst::composition {
|
||||
std::optional<double> Ye; ///< Cached electron abundance.
|
||||
|
||||
void clear() {
|
||||
globalComp = std::nullopt;
|
||||
canonicalComp = std::nullopt;
|
||||
massFractions = std::nullopt;
|
||||
numberFractions = std::nullopt;
|
||||
@@ -277,7 +122,7 @@ namespace fourdst::composition {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_clear() const {
|
||||
return !globalComp.has_value() && !canonicalComp.has_value() && !massFractions.has_value() &&
|
||||
return !canonicalComp.has_value() && !massFractions.has_value() &&
|
||||
!numberFractions.has_value() && !molarAbundances.has_value() && !sortedSymbols.has_value() &&
|
||||
!Ye.has_value() && !sortedSpecies.has_value();
|
||||
}
|
||||
@@ -289,52 +134,11 @@ namespace fourdst::composition {
|
||||
return logger;
|
||||
}
|
||||
|
||||
bool m_finalized = false; ///< True if the composition is finalized.
|
||||
double m_specificNumberDensity = 0.0; ///< The specific number density of the composition (\sum_{i} X_i m_i. Where X_i is the number fraction of the ith species and m_i is the mass of the ith species).
|
||||
double m_meanParticleMass = 0.0; ///< The mean particle mass of the composition (\sum_{i} \frac{n_i}{m_i}. where n_i is the number fraction of the ith species and m_i is the mass of the ith species).
|
||||
bool m_massFracMode = true; ///< True if mass fraction mode, false if number fraction mode.
|
||||
|
||||
std::set<std::string> m_registeredSymbols; ///< The registered symbols.
|
||||
std::unordered_map<std::string, CompositionEntry> m_compositions; ///< The compositions.
|
||||
std::set<atomic::Species> m_registeredSpecies;
|
||||
std::map<atomic::Species, double> m_molarAbundances;
|
||||
|
||||
mutable CompositionCache m_cache; ///< Cache for computed properties to avoid redundant calculations.
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if the given symbol is valid by checking against the global species database.
|
||||
* @param symbol The symbol to check.
|
||||
* @return True if the symbol is valid, false otherwise.
|
||||
*/
|
||||
static bool isValidSymbol(const std::string& symbol);
|
||||
|
||||
/**
|
||||
* @brief Checks if the given fractions are valid (sum to ~1.0).
|
||||
* @param fractions The fractions to check.
|
||||
* @return True if the fractions are valid, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool isValidComposition(const std::vector<double>& fractions) ;
|
||||
|
||||
/**
|
||||
* @brief Validates the given fractions, throwing an exception on failure.
|
||||
* @param fractions The fractions to validate.
|
||||
* @throws exceptions::InvalidCompositionError if the fractions are invalid.
|
||||
*/
|
||||
static void validateComposition(const std::vector<double>& fractions) ;
|
||||
|
||||
/**
|
||||
* @brief Finalizes the composition in mass fraction mode.
|
||||
* @param norm If true, the composition will be normalized to sum to 1.
|
||||
* @return True if the composition is successfully finalized, false otherwise.
|
||||
*/
|
||||
bool finalizeMassFracMode(bool norm);
|
||||
|
||||
/**
|
||||
* @brief Finalizes the composition in number fraction mode.
|
||||
* @param norm If true, the composition will be normalized to sum to 1.
|
||||
* @return True if the composition is successfully finalized, false otherwise.
|
||||
*/
|
||||
bool finalizeNumberFracMode(bool norm);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
@@ -346,17 +150,6 @@ namespace fourdst::composition {
|
||||
*/
|
||||
~Composition() override = default;
|
||||
|
||||
/**
|
||||
* @brief Finalizes the composition, making it ready for querying.
|
||||
* @details This method checks if the sum of all fractions (mass or number) is approximately 1.0.
|
||||
* It also computes global properties like mean particle mass. This **must** be called before
|
||||
* any `get...` method can be used.
|
||||
* @param norm If true, the composition will be normalized to sum to 1 before validation. [Default: false]
|
||||
* @return True if the composition is valid and successfully finalized, false otherwise.
|
||||
* @post If successful, `m_finalized` is true and global properties are computed.
|
||||
*/
|
||||
[[nodiscard]] bool finalize(bool norm=false);
|
||||
|
||||
/**
|
||||
* @brief Constructs a Composition and registers the given symbols.
|
||||
* @param symbols The symbols to register. The composition will be in mass fraction mode by default.
|
||||
@@ -372,6 +165,8 @@ namespace fourdst::composition {
|
||||
*/
|
||||
explicit Composition(const std::vector<std::string>& symbols);
|
||||
|
||||
explicit Composition(const std::vector<atomic::Species>& species);
|
||||
|
||||
/**
|
||||
* @brief Constructs a Composition and registers the given symbols from a set.
|
||||
* @param symbols The symbols to register. The composition will be in mass fraction mode by default.
|
||||
@@ -384,13 +179,14 @@ namespace fourdst::composition {
|
||||
*/
|
||||
explicit Composition(const std::set<std::string>& symbols);
|
||||
|
||||
explicit Composition(const std::set<atomic::Species>& species);
|
||||
|
||||
/**
|
||||
* @brief Constructs and finalizes a Composition with the given symbols and fractions.
|
||||
* @details This constructor provides a convenient way to create a fully-formed, finalized composition in one step.
|
||||
* The provided fractions must be valid and sum to 1.0.
|
||||
* @param symbols The symbols to initialize the composition with.
|
||||
* @param fractions The fractions (mass or number) corresponding to the symbols.
|
||||
* @param massFracMode True if `fractions` are mass fractions, false if they are number fractions. [Default: true]
|
||||
* @param molarAbundances The corresponding molar abundances for each symbol.
|
||||
* @throws exceptions::InvalidCompositionError if the number of symbols and fractions do not match, or if the fractions do not sum to ~1.0.
|
||||
* @throws exceptions::InvalidSymbolError if any symbol is invalid.
|
||||
* @post The composition is immediately finalized.
|
||||
@@ -401,7 +197,11 @@ namespace fourdst::composition {
|
||||
* Composition comp(symbols, mass_fractions); // Finalized on construction
|
||||
* @endcode
|
||||
*/
|
||||
Composition(const std::vector<std::string>& symbols, const std::vector<double>& fractions, bool massFracMode=true);
|
||||
Composition(const std::vector<std::string>& symbols, const std::vector<double>& molarAbundances);
|
||||
|
||||
Composition(const std::vector<atomic::Species>& species, const std::vector<double>& molarAbundances);
|
||||
|
||||
Composition(const std::set<std::string>& symbols, const std::vector<double>& molarAbundances);
|
||||
|
||||
/**
|
||||
* @brief Constructs a Composition from another Composition.
|
||||
@@ -420,7 +220,6 @@ namespace fourdst::composition {
|
||||
* @brief Registers a new symbol for inclusion in the composition.
|
||||
* @details A symbol must be registered before its abundance can be set. The first registration sets the mode (mass/number fraction) for the entire composition.
|
||||
* @param symbol The symbol to register (e.g., "Fe-56").
|
||||
* @param massFracMode True for mass fraction mode, false for number fraction mode. This is only effective for the first symbol registered.
|
||||
* @throws exceptions::InvalidSymbolError if the symbol is not in the atomic species database.
|
||||
* @throws exceptions::CompositionModeError if attempting to register with a mode that conflicts with the existing mode.
|
||||
* @par Usage Example:
|
||||
@@ -430,12 +229,11 @@ namespace fourdst::composition {
|
||||
* comp.registerSymbol("He-4"); // Must also be mass fraction mode
|
||||
* @endcode
|
||||
*/
|
||||
void registerSymbol(const std::string& symbol, bool massFracMode=true);
|
||||
void registerSymbol(const std::string& symbol);
|
||||
|
||||
/**
|
||||
* @brief Registers multiple new symbols.
|
||||
* @param symbols The symbols to register.
|
||||
* @param massFracMode True for mass fraction mode, false for number fraction mode.
|
||||
* @throws exceptions::InvalidSymbolError if any symbol is invalid.
|
||||
* @throws exceptions::CompositionModeError if the mode conflicts with an already set mode.
|
||||
* @par Usage Example:
|
||||
@@ -445,12 +243,11 @@ namespace fourdst::composition {
|
||||
* comp.registerSymbol(symbols);
|
||||
* @endcode
|
||||
*/
|
||||
void registerSymbol(const std::vector<std::string>& symbols, bool massFracMode=true);
|
||||
void registerSymbol(const std::vector<std::string>& symbols);
|
||||
|
||||
/**
|
||||
* @brief Registers a new species by extracting its symbol.
|
||||
* @param species The species to register.
|
||||
* @param massFracMode True for mass fraction mode, false for number fraction mode.
|
||||
* @throws exceptions::InvalidSymbolError if the species' symbol is invalid.
|
||||
* @throws exceptions::CompositionModeError if the mode conflicts.
|
||||
* @par Usage Example:
|
||||
@@ -460,13 +257,12 @@ namespace fourdst::composition {
|
||||
* comp.registerSpecies(fourdst::atomic::species.at("H-1"));
|
||||
* @endcode
|
||||
*/
|
||||
void registerSpecies(const fourdst::atomic::Species& species, bool massFracMode=true);
|
||||
void registerSpecies(const atomic::Species& species);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Registers a vector of new species.
|
||||
* @param species The vector of species to register.
|
||||
* @param massFracMode True for mass fraction mode, false for number fraction mode.
|
||||
* @throws exceptions::InvalidSymbolError if any species' symbol is invalid.
|
||||
* @throws exceptions::CompositionModeError if the mode conflicts.
|
||||
* @par Usage Example:
|
||||
@@ -477,8 +273,50 @@ namespace fourdst::composition {
|
||||
* comp.registerSpecies(my_species, false); // Number fraction mode
|
||||
* @endcode
|
||||
*/
|
||||
void registerSpecies(const std::vector<fourdst::atomic::Species>& species, bool massFracMode=true);
|
||||
void registerSpecies(const std::vector<atomic::Species>& species);
|
||||
|
||||
/**
|
||||
* @brief Checks if a given isotope is present in the composition.
|
||||
* @pre The composition must be finalized.
|
||||
* @param species The isotope to check for.
|
||||
* @return True if the isotope is in the composition, false otherwise.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const atomic::Species& species) const override;
|
||||
|
||||
[[nodiscard]] bool contains(const std::string& symbol) const override;
|
||||
|
||||
[[nodiscard]] size_t size() const override;
|
||||
|
||||
void setMolarAbundance(
|
||||
const std::string& symbol,
|
||||
const double& molar_abundance
|
||||
);
|
||||
|
||||
void setMolarAbundance(
|
||||
const atomic::Species& species,
|
||||
const double& molar_abundance
|
||||
);
|
||||
|
||||
void setMolarAbundance(
|
||||
const std::vector<std::string>& symbols,
|
||||
const std::vector<double>& molar_abundances
|
||||
);
|
||||
|
||||
void setMolarAbundance(
|
||||
const std::vector<atomic::Species>& species,
|
||||
const std::vector<double>& molar_abundances
|
||||
);
|
||||
|
||||
void setMolarAbundance(
|
||||
const std::set<std::string>& symbols,
|
||||
const std::vector<double>& molar_abundances
|
||||
);
|
||||
|
||||
void setMolarAbundance(
|
||||
const std::set<atomic::Species>& species,
|
||||
const std::vector<double>& molar_abundances
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Gets the registered symbols.
|
||||
@@ -490,112 +328,7 @@ namespace fourdst::composition {
|
||||
* @brief Get a set of all species that are registered in the composition.
|
||||
* @return A set of `atomic::Species` objects registered in the composition.
|
||||
*/
|
||||
[[nodiscard]] std::set<fourdst::atomic::Species> getRegisteredSpecies() const override;
|
||||
|
||||
/**
|
||||
* @brief Sets the mass fraction for a given symbol.
|
||||
* @param symbol The symbol to set the mass fraction for.
|
||||
* @param mass_fraction The mass fraction to set (must be in [0, 1]).
|
||||
* @return The previous mass fraction that was set for the symbol.
|
||||
* @throws exceptions::UnregisteredSymbolError if the symbol is not registered.
|
||||
* @throws exceptions::CompositionModeError if the composition is in number fraction mode.
|
||||
* @throws exceptions::InvalidCompositionError if the mass fraction is not between 0 and 1.
|
||||
* @post The composition is marked as not finalized.
|
||||
* @par Usage Example:
|
||||
* @code
|
||||
* Composition comp;
|
||||
* comp.registerSymbol("H-1");
|
||||
* comp.setMassFraction("H-1", 0.7);
|
||||
* @endcode
|
||||
*/
|
||||
double setMassFraction(const std::string& symbol, const double& mass_fraction);
|
||||
|
||||
/**
|
||||
* @brief Sets the mass fraction for multiple symbols.
|
||||
* @param symbols The symbols to set the mass fractions for.
|
||||
* @param mass_fractions The mass fractions corresponding to the symbols.
|
||||
* @return A vector of the previous mass fractions that were set.
|
||||
* @throws exceptions::InvalidCompositionError if symbol and fraction counts differ.
|
||||
* @throws See `setMassFraction(const std::string&, const double&)` for other exceptions.
|
||||
* @post The composition is marked as not finalized.
|
||||
*/
|
||||
std::vector<double> setMassFraction(const std::vector<std::string>& symbols, const std::vector<double>& mass_fractions);
|
||||
|
||||
/**
|
||||
* @brief Sets the mass fraction for a given species.
|
||||
* @param species The species to set the mass fraction for.
|
||||
* @param mass_fraction The mass fraction to set.
|
||||
* @return The previous mass fraction that was set for the species.
|
||||
* @throws exceptions::UnregisteredSymbolError if the species is not registered.
|
||||
* @throws exceptions::CompositionModeError if the composition is in number fraction mode.
|
||||
* @throws exceptions::InvalidCompositionError if the mass fraction is not between 0 and 1.
|
||||
*/
|
||||
double setMassFraction(const fourdst::atomic::Species& species, const double& mass_fraction);
|
||||
|
||||
/**
|
||||
* @brief Sets the mass fraction for multiple species.
|
||||
* @param species The vector of species to set the mass fractions for.
|
||||
* @param mass_fractions The vector of mass fractions corresponding to the species.
|
||||
* @return A vector of the previous mass fractions that were set.
|
||||
* @throws See `setMassFraction(const std::vector<std::string>&, const std::vector<double>&)` for exceptions.
|
||||
*/
|
||||
std::vector<double> setMassFraction(const std::vector<fourdst::atomic::Species>& species, const std::vector<double>& mass_fractions);
|
||||
|
||||
/**
|
||||
* @brief Sets the number fraction for a given symbol.
|
||||
* @param symbol The symbol to set the number fraction for.
|
||||
* @param number_fraction The number fraction to set (must be in [0, 1]).
|
||||
* @return The previous number fraction that was set.
|
||||
* @throws exceptions::UnregisteredSymbolError if the symbol is not registered.
|
||||
* @throws exceptions::CompositionModeError if the composition is in mass fraction mode.
|
||||
* @throws exceptions::InvalidCompositionError if the number fraction is not between 0 and 1.
|
||||
* @post The composition is marked as not finalized.
|
||||
*/
|
||||
double setNumberFraction(const std::string& symbol, const double& number_fraction);
|
||||
|
||||
/**
|
||||
* @brief Sets the number fraction for multiple symbols.
|
||||
* @param symbols The symbols to set the number fractions for.
|
||||
* @param number_fractions The number fractions corresponding to the symbols.
|
||||
* @return A vector of the previous number fractions that were set.
|
||||
* @throws exceptions::InvalidCompositionError if symbol and fraction counts differ.
|
||||
* @throws See `setNumberFraction(const std::string&, const double&)` for other exceptions.
|
||||
*/
|
||||
std::vector<double> setNumberFraction(const std::vector<std::string>& symbols, const std::vector<double>& number_fractions);
|
||||
|
||||
/**
|
||||
* @brief Sets the number fraction for a given species.
|
||||
* @param species The species to set the number fraction for.
|
||||
* @param number_fraction The number fraction to set for the species.
|
||||
* @return The previous number fraction that was set for the species.
|
||||
* @throws exceptions::UnregisteredSymbolError if the species is not registered.
|
||||
* @throws exceptions::CompositionModeError if the composition is in mass fraction mode.
|
||||
* @throws exceptions::InvalidCompositionError if the number fraction is not between 0 and 1.
|
||||
*/
|
||||
double setNumberFraction(const fourdst::atomic::Species& species, const double& number_fraction);
|
||||
|
||||
/**
|
||||
* @brief Sets the number fraction for multiple species.
|
||||
* @param species The vector of species to set the number fractions for.
|
||||
* @param number_fractions The vector of number fractions corresponding to the species.
|
||||
* @return The vector of the previous number fractions that were set.
|
||||
* @throws See `setNumberFraction(const std::vector<std::string>&, const std::vector<double>&)` for exceptions.
|
||||
*/
|
||||
std::vector<double> setNumberFraction(const std::vector<fourdst::atomic::Species>& species, const std::vector<double>& number_fractions);
|
||||
|
||||
/**
|
||||
* @brief Mixes this composition with another to produce a new composition.
|
||||
* @details The mixing is performed linearly on the mass fractions. The formula for each species is:
|
||||
* `new_X_i = fraction * this_X_i + (1 - fraction) * other_X_i`.
|
||||
* The resulting composition is automatically finalized.
|
||||
* @param other The other composition to mix with.
|
||||
* @param fraction The mixing fraction. A value of 1.0 means the new composition is 100% `this`, 0.0 means 100% `other`.
|
||||
* @return A new, finalized `Composition` object representing the mixture.
|
||||
* @pre Both `this` and `other` compositions must be finalized.
|
||||
* @throws exceptions::CompositionNotFinalizedError if either composition is not finalized.
|
||||
* @throws exceptions::InvalidCompositionError if the fraction is not between 0 and 1.
|
||||
*/
|
||||
[[nodiscard]] Composition mix(const Composition& other, double fraction) const;
|
||||
[[nodiscard]] const std::set<atomic::Species> &getRegisteredSpecies() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the mass fractions of all species in the composition.
|
||||
@@ -603,7 +336,7 @@ namespace fourdst::composition {
|
||||
* @return An unordered map of symbols to their mass fractions.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_map<std::string, double> getMassFraction() const override;
|
||||
[[nodiscard]] std::unordered_map<atomic::Species, double> getMassFraction() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the mass fraction for a given symbol.
|
||||
@@ -651,7 +384,7 @@ namespace fourdst::composition {
|
||||
* @return An unordered map of symbols to their number fractions.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
*/
|
||||
[[nodiscard]] std::unordered_map<std::string, double> getNumberFraction() const override;
|
||||
[[nodiscard]] std::unordered_map<atomic::Species, double> getNumberFraction() const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the molar abundance (X_i / A_i) for a given symbol.
|
||||
@@ -671,35 +404,7 @@ namespace fourdst::composition {
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
* @throws exceptions::UnregisteredSymbolError if the isotope is not registered in the composition.
|
||||
*/
|
||||
[[nodiscard]] double getMolarAbundance(const fourdst::atomic::Species& species) const override;
|
||||
|
||||
/**
|
||||
* @brief Gets the composition entry and global composition data for a given symbol.
|
||||
* @pre The composition must be finalized.
|
||||
* @param symbol The symbol to get the composition for.
|
||||
* @return A pair containing the CompositionEntry and GlobalComposition for the given symbol.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
* @throws exceptions::UnregisteredSymbolError if the symbol is not in the composition.
|
||||
*/
|
||||
[[nodiscard]] std::pair<CompositionEntry, GlobalComposition> getComposition(const std::string& symbol) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the composition entry and global composition data for a given species.
|
||||
* @pre The composition must be finalized.
|
||||
* @param species The species to get the composition for.
|
||||
* @return A pair containing the CompositionEntry and GlobalComposition for the given species.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
* @throws exceptions::UnregisteredSymbolError if the species is not in the composition.
|
||||
*/
|
||||
[[nodiscard]] std::pair<CompositionEntry, GlobalComposition> getComposition(const fourdst::atomic::Species& species) const;
|
||||
|
||||
/**
|
||||
* @brief Gets all composition entries and the global composition data.
|
||||
* @pre The composition must be finalized.
|
||||
* @return A pair containing an unordered map of all CompositionEntries and the GlobalComposition.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
*/
|
||||
[[nodiscard]] std::pair<std::unordered_map<std::string, CompositionEntry>, GlobalComposition> getComposition() const;
|
||||
[[nodiscard]] double getMolarAbundance(const atomic::Species& species) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute the mean particle mass of the composition.
|
||||
@@ -709,14 +414,6 @@ namespace fourdst::composition {
|
||||
*/
|
||||
[[nodiscard]] double getMeanParticleMass() const override;
|
||||
|
||||
/**
|
||||
* @brief Compute the mean atomic number of the composition.
|
||||
* @pre The composition must be finalized.
|
||||
* @return Mean atomic number <Z>.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
*/
|
||||
[[nodiscard]] double getMeanAtomicNumber() const override;
|
||||
|
||||
/**
|
||||
* @brief Compute the electron abundance of the composition.
|
||||
* @details Ye is defined as the sum over all species of (Z_i * X_i / A_i), where Z_i is the atomic number, X_i is the mass fraction, and A_i is the atomic mass of species i.
|
||||
@@ -725,49 +422,6 @@ namespace fourdst::composition {
|
||||
*/
|
||||
[[nodiscard]] double getElectronAbundance() const override;
|
||||
|
||||
/**
|
||||
* @brief Creates a new Composition object containing a subset of species from this one.
|
||||
* @param symbols The symbols to include in the subset.
|
||||
* @param method The method for handling the abundances of the new subset. Can be "norm" (normalize abundances to sum to 1) or "none" (keep original abundances).
|
||||
* @return A new `Composition` object containing the subset.
|
||||
* @throws exceptions::UnregisteredSymbolError if any requested symbol is not in the original composition.
|
||||
* @throws exceptions::InvalidMixingMode if an invalid method is provided.
|
||||
* @throws exceptions::FailedToFinalizeCompositionError if normalization fails.
|
||||
*/
|
||||
[[nodiscard]] Composition subset(const std::vector<std::string>& symbols, const std::string& method="norm") const;
|
||||
|
||||
/**
|
||||
* @brief Checks if a symbol is registered in the composition.
|
||||
* @param symbol The symbol to check.
|
||||
* @return True if the symbol is registered, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool hasSymbol(const std::string& symbol) const override;
|
||||
|
||||
/**
|
||||
* @brief Checks if a species is registered in the composition.
|
||||
* @param species The species to check.
|
||||
* @return True if the species is registered, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool hasSpecies(const fourdst::atomic::Species &species) const override;
|
||||
|
||||
/**
|
||||
* @brief Checks if a given isotope is present in the composition.
|
||||
* @pre The composition must be finalized.
|
||||
* @param isotope The isotope to check for.
|
||||
* @return True if the isotope is in the composition, false otherwise.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const atomic::Species& isotope) const override;
|
||||
|
||||
/**
|
||||
* @brief Sets the composition mode (mass fraction vs. number fraction).
|
||||
* @details This function converts all entries in the composition to the specified mode.
|
||||
* @pre The composition must be finalized before the mode can be switched.
|
||||
* @param massFracMode True to switch to mass fraction mode, false for number fraction mode.
|
||||
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
|
||||
* @throws std::runtime_error if the conversion fails for an unknown reason.
|
||||
*/
|
||||
void setCompositionMode(bool massFracMode);
|
||||
|
||||
/**
|
||||
* @brief Gets the current canonical composition (X, Y, Z).
|
||||
@@ -850,22 +504,12 @@ namespace fourdst::composition {
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& os, const Composition& composition);
|
||||
|
||||
/**
|
||||
* @brief Overloads the + operator to mix two compositions with a 50/50 fraction.
|
||||
* @details This is a convenience operator that calls `mix(other, 0.5)`.
|
||||
* @param other The other composition to mix with.
|
||||
* @return The new, mixed composition.
|
||||
* @pre Both compositions must be finalized.
|
||||
* @throws See `mix()` for exceptions.
|
||||
*/
|
||||
Composition operator+(const Composition& other) const;
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of the composition map.
|
||||
* @return An iterator to the beginning.
|
||||
*/
|
||||
auto begin() {
|
||||
return m_compositions.begin();
|
||||
return m_molarAbundances.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -873,7 +517,7 @@ namespace fourdst::composition {
|
||||
* @return A const iterator to the beginning.
|
||||
*/
|
||||
[[nodiscard]] auto begin() const {
|
||||
return m_compositions.cbegin();
|
||||
return m_molarAbundances.cbegin();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -881,7 +525,7 @@ namespace fourdst::composition {
|
||||
* @return An iterator to the end.
|
||||
*/
|
||||
auto end() {
|
||||
return m_compositions.end();
|
||||
return m_molarAbundances.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -889,7 +533,7 @@ namespace fourdst::composition {
|
||||
* @return A const iterator to the end.
|
||||
*/
|
||||
[[nodiscard]] auto end() const {
|
||||
return m_compositions.cend();
|
||||
return m_molarAbundances.cend();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@@ -36,20 +36,6 @@ public:
|
||||
*/
|
||||
virtual ~CompositionAbstract() = default;
|
||||
|
||||
/**
|
||||
* @brief Check if a chemical symbol is registered in the composition.
|
||||
* @param symbol The chemical symbol to check (e.g., "H", "He").
|
||||
* @return True if the symbol is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] virtual bool hasSymbol(const std::string& symbol) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if a species is registered in the composition.
|
||||
* @param species The atomic species to check.
|
||||
* @return True if the species is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] virtual bool hasSpecies(const fourdst::atomic::Species& species) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if the composition contains the given species.
|
||||
* @param species The atomic species to check.
|
||||
@@ -57,6 +43,15 @@ public:
|
||||
*/
|
||||
[[nodiscard]] virtual bool contains(const fourdst::atomic::Species& species) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Check if the composition contains the given species.
|
||||
* @param symbol The symbol of the atomic species to check.
|
||||
* @return True if the species is contained, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] virtual bool contains(const std::string& symbol) const = 0;
|
||||
|
||||
[[nodiscard]] virtual size_t size() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get all registered chemical symbols in the composition.
|
||||
* @return A set of registered chemical symbols.
|
||||
@@ -67,19 +62,19 @@ public:
|
||||
* @brief Get all registered atomic species in the composition.
|
||||
* @return A set of registered atomic species.
|
||||
*/
|
||||
[[nodiscard]] virtual std::set<fourdst::atomic::Species> getRegisteredSpecies() const = 0;
|
||||
[[nodiscard]] virtual const std::set<fourdst::atomic::Species> &getRegisteredSpecies() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the mass fraction for all registered symbols.
|
||||
* @return An unordered map from symbol to mass fraction.
|
||||
*/
|
||||
[[nodiscard]] virtual std::unordered_map<std::string, double> getMassFraction() const = 0;
|
||||
[[nodiscard]] virtual std::unordered_map<fourdst::atomic::Species, double> getMassFraction() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the number fraction for all registered symbols.
|
||||
* @return An unordered map from symbol to number fraction.
|
||||
*/
|
||||
[[nodiscard]] virtual std::unordered_map<std::string, double> getNumberFraction() const = 0;
|
||||
[[nodiscard]] virtual std::unordered_map<fourdst::atomic::Species, double> getNumberFraction() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the mass fraction for a given symbol.
|
||||
@@ -129,12 +124,6 @@ public:
|
||||
*/
|
||||
[[nodiscard]] virtual double getMeanParticleMass() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the mean atomic number of the composition.
|
||||
* @return The mean atomic number.
|
||||
*/
|
||||
[[nodiscard]] virtual double getMeanAtomicNumber() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the electron abundance of the composition.
|
||||
* @return The electron abundance.
|
||||
|
||||
@@ -94,14 +94,6 @@ namespace fourdst::composition::exceptions {
|
||||
using CompositionError::CompositionError;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class InvalidSymbolError
|
||||
* @brief Exception thrown when a symbol used in a composition is invalid.
|
||||
*/
|
||||
class InvalidSymbolError final : public CompositionError {
|
||||
using CompositionError::CompositionError;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class UnregisteredSymbolError
|
||||
* @brief Exception thrown when a symbol is used that has not been registered.
|
||||
@@ -146,4 +138,20 @@ namespace fourdst::composition::exceptions {
|
||||
using CompositionEntryError::CompositionEntryError;
|
||||
};
|
||||
|
||||
class SpeciesError : public std::exception {
|
||||
protected:
|
||||
std::string m_message;
|
||||
public:
|
||||
explicit SpeciesError(const std::string& message)
|
||||
: m_message(std::move(message)) {}
|
||||
|
||||
const char* what() const noexcept override {
|
||||
return m_message.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class UnknownSymbolError final : public SpeciesError {
|
||||
using SpeciesError::SpeciesError;
|
||||
};
|
||||
|
||||
}
|
||||
23
src/composition/include/fourdst/composition/utils.h
Normal file
23
src/composition/include/fourdst/composition/utils.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace fourdst::composition {
|
||||
Composition buildCompositionFromMassFractions(
|
||||
const std::vector<std::string>& symbols,
|
||||
const std::vector<double>& massFractions
|
||||
);
|
||||
|
||||
Composition buildCompositionFromMassFractions(
|
||||
const std::vector<atomic::Species>& species,
|
||||
const std::vector<double>& massFractions
|
||||
);
|
||||
|
||||
Composition buildCompositionFromMassFractions(
|
||||
const std::set<atomic::Species>& species,
|
||||
const std::vector<double>& massFractions
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
58
src/composition/lib/utils.cpp
Normal file
58
src/composition/lib/utils.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/composition/exceptions/exceptions_composition.h"
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
#include "fourdst/atomic/species.h"
|
||||
#include "fourdst/composition/utils.h"
|
||||
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
std::optional<fourdst::atomic::Species> getSpecies(const std::string& symbol) {
|
||||
if (!fourdst::atomic::species.contains(symbol)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return fourdst::atomic::species.at(symbol);
|
||||
}
|
||||
|
||||
void throw_unknown_symbol(quill::Logger* logger, const std::string& symbol) {
|
||||
throw fourdst::composition::exceptions::UnknownSymbolError("Symbol " + symbol + " is not a valid species symbol (not in the species database)");
|
||||
}
|
||||
}
|
||||
|
||||
namespace fourdst::composition {
|
||||
Composition buildCompositionFromMassFractions(
|
||||
const std::set<atomic::Species> &species,
|
||||
const std::vector<double> &massFractions
|
||||
) {
|
||||
Composition composition;
|
||||
|
||||
for (const auto& [sp, xi] : std::views::zip(species, massFractions)) {
|
||||
composition.registerSpecies(sp);
|
||||
composition.setMolarAbundance(sp, xi/sp.mass());
|
||||
}
|
||||
|
||||
return composition;
|
||||
}
|
||||
|
||||
Composition buildCompositionFromMassFractions(const std::vector<atomic::Species> &species, const std::vector<double> &massFractions) {
|
||||
return buildCompositionFromMassFractions(std::set<atomic::Species>(species.begin(), species.end()), massFractions);
|
||||
}
|
||||
|
||||
Composition buildCompositionFromMassFractions(const std::vector<std::string> &symbols, const std::vector<double> &massFractions) {
|
||||
std::set<atomic::Species> species;
|
||||
for (const auto& symbol : symbols) {
|
||||
auto result = getSpecies(symbol);
|
||||
if (!result) {
|
||||
throw_unknown_symbol(nullptr, symbol);
|
||||
}
|
||||
species.insert(result.value());
|
||||
}
|
||||
return buildCompositionFromMassFractions(species, massFractions);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
required_headers = [
|
||||
'fourdst/composition/atomicSpecies.h',
|
||||
'fourdst/composition/species.h',
|
||||
'fourdst/composition/composition.h'
|
||||
'fourdst/composition/composition.h',
|
||||
'fourdst/composition/utils.h',
|
||||
'fourdst/composition/composition_abstract.h',
|
||||
'fourdst/composition/exceptions/exceptions_composition.h'
|
||||
]
|
||||
|
||||
foreach h : required_headers
|
||||
@@ -18,6 +21,7 @@ message('✅ libcomposition species_weight dependency declared')
|
||||
|
||||
composition_sources = files(
|
||||
'lib/composition.cpp',
|
||||
'lib/utils.cpp',
|
||||
)
|
||||
|
||||
|
||||
@@ -44,12 +48,21 @@ composition_dep = declare_dependency(
|
||||
# Make headers accessible
|
||||
composition_headers = files(
|
||||
'include/fourdst/composition/composition.h',
|
||||
'include/fourdst/composition/atomicSpecies.h',
|
||||
'include/fourdst/composition/species.h',
|
||||
'include/fourdst/composition/elements.h'
|
||||
)
|
||||
install_headers(composition_headers, subdir : 'fourdst/fourdst/composition')
|
||||
|
||||
composition_headers_utils = files(
|
||||
'include/fourdst/composition/utils.h',
|
||||
)
|
||||
install_headers(composition_headers_utils, subdir : 'fourdst/fourdst/composition/utils')
|
||||
|
||||
composition_headers_atomic = files(
|
||||
'include/fourdst/atomic/atomicSpecies.h',
|
||||
'include/fourdst/atomic/elements.h',
|
||||
'include/fourdst/atomic/species.h',
|
||||
)
|
||||
install_headers(composition_headers_atomic, subdir : 'fourdst/fourdst/atomic')
|
||||
|
||||
composition_exception_headers = files(
|
||||
'include/fourdst/composition/exceptions/exceptions_composition.h',
|
||||
)
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
#include "fourdst/composition/species.h"
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
#include "fourdst/atomic/species.h"
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/composition/exceptions/exceptions_composition.h"
|
||||
#include "fourdst/composition/utils.h"
|
||||
|
||||
#include "fourdst/config/config.h"
|
||||
|
||||
std::string EXAMPLE_FILENAME = std::string(getenv("MESON_SOURCE_ROOT")) + "/tests/config/example.yaml";
|
||||
|
||||
/**
|
||||
* @brief Test suite for the Composition class and related data structures.
|
||||
@@ -92,7 +92,6 @@ TEST_F(compositionTest, isotopeSpin) {
|
||||
* - The state of the constructed object or the correctness of its methods.
|
||||
*/
|
||||
TEST_F(compositionTest, constructor) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
EXPECT_NO_THROW(fourdst::composition::Composition comp);
|
||||
}
|
||||
|
||||
@@ -108,12 +107,11 @@ TEST_F(compositionTest, constructor) {
|
||||
* - The handling of mode conflicts (e.g., trying to register a symbol in number fraction mode when the composition is already in mass fraction mode).
|
||||
*/
|
||||
TEST_F(compositionTest, registerSymbol) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
EXPECT_NO_THROW(comp.registerSymbol("H-1"));
|
||||
EXPECT_NO_THROW(comp.registerSymbol("He-4"));
|
||||
EXPECT_THROW(comp.registerSymbol("H-19"), fourdst::composition::exceptions::InvalidSymbolError);
|
||||
EXPECT_THROW(comp.registerSymbol("He-21"), fourdst::composition::exceptions::InvalidSymbolError);
|
||||
EXPECT_THROW(comp.registerSymbol("H-19"), fourdst::composition::exceptions::UnknownSymbolError);
|
||||
EXPECT_THROW(comp.registerSymbol("He-21"), fourdst::composition::exceptions::UnknownSymbolError);
|
||||
|
||||
std::set<std::string> registeredSymbols = comp.getRegisteredSymbols();
|
||||
EXPECT_TRUE(registeredSymbols.contains("H-1"));
|
||||
@@ -136,276 +134,29 @@ TEST_F(compositionTest, registerSymbol) {
|
||||
* - The correctness of number fraction mode, which is tested separately.
|
||||
*/
|
||||
TEST_F(compositionTest, setGetComposition) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
// fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
EXPECT_NO_THROW(comp.registerSymbol("H-1"));
|
||||
EXPECT_NO_THROW(comp.registerSymbol("He-4"));
|
||||
|
||||
EXPECT_DOUBLE_EQ(comp.setMassFraction("H-1", 0.5), 0.0);
|
||||
EXPECT_DOUBLE_EQ(comp.setMassFraction("He-4", 0.5), 0.0);
|
||||
EXPECT_DOUBLE_EQ(comp.setMassFraction("H-1", 0.6), 0.5);
|
||||
EXPECT_DOUBLE_EQ(comp.setMassFraction("He-4", 0.4), 0.5);
|
||||
EXPECT_NO_THROW(comp.setMolarAbundance("H-1", 0.6));
|
||||
EXPECT_NO_THROW(comp.setMolarAbundance("He-4", 0.4));
|
||||
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.6);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.27414655751871775);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("He-4"), 0.7258534424812823);
|
||||
|
||||
EXPECT_THROW(comp.setMassFraction("He-3", 0.3), fourdst::composition::exceptions::UnregisteredSymbolError);
|
||||
EXPECT_THROW(comp.setMolarAbundance("He-3", 0.3), fourdst::composition::exceptions::UnregisteredSymbolError);
|
||||
|
||||
const std::vector<std::string> symbols = {"H-1", "He-4"};
|
||||
EXPECT_NO_THROW(comp.registerSymbol("C-12"));
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.27414655751871775);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("He-4"), 0.7258534424812823);
|
||||
|
||||
EXPECT_NO_THROW(comp.setMassFraction(symbols, {0.5, 0.5}));
|
||||
EXPECT_THROW(auto r = comp.getComposition("H-1"), fourdst::composition::exceptions::CompositionNotFinalizedError);
|
||||
EXPECT_TRUE(comp.finalize());
|
||||
EXPECT_DOUBLE_EQ(comp.getComposition("H-1").first.mass_fraction(), 0.5);
|
||||
EXPECT_NO_THROW(comp.setMolarAbundance("C-12", 0.1));
|
||||
|
||||
EXPECT_NO_THROW(comp.setMassFraction(symbols, {0.6, 0.6}));
|
||||
EXPECT_FALSE(comp.finalize());
|
||||
EXPECT_THROW(auto r = comp.getComposition("H-1"), fourdst::composition::exceptions::CompositionNotFinalizedError);
|
||||
}
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.177551918933757);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("He-4"), 0.4701013674717613);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("C-12"), 0.3523467135944818);
|
||||
|
||||
/**
|
||||
* @brief Tests the workflow of setting and getting number fractions.
|
||||
* @details This test mirrors `setGetComposition` but for number fraction mode. It verifies
|
||||
* that symbols can be registered in number fraction mode and that `setNumberFraction` and
|
||||
* `getNumberFraction` work as expected.
|
||||
* @par What this test proves:
|
||||
* - The composition can be correctly initialized and operated in number fraction mode.
|
||||
* - `setNumberFraction` and `getNumberFraction` function correctly.
|
||||
* - An attempt to set a fraction for an unregistered symbol throws the correct exception.
|
||||
* @par What this test does not prove:
|
||||
* - The correctness of conversions between mass and number fraction modes.
|
||||
*/
|
||||
TEST_F(compositionTest, setGetNumberFraction) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1", false);
|
||||
comp.registerSymbol("He-4", false);
|
||||
|
||||
EXPECT_DOUBLE_EQ(comp.setNumberFraction("H-1", 0.5), 0.0);
|
||||
EXPECT_DOUBLE_EQ(comp.setNumberFraction("He-4", 0.5), 0.0);
|
||||
EXPECT_DOUBLE_EQ(comp.setNumberFraction("H-1", 0.6), 0.5);
|
||||
EXPECT_DOUBLE_EQ(comp.setNumberFraction("He-4", 0.4), 0.5);
|
||||
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
EXPECT_DOUBLE_EQ(comp.getNumberFraction("H-1"), 0.6);
|
||||
|
||||
EXPECT_THROW(comp.setNumberFraction("He-3", 0.3), fourdst::composition::exceptions::UnregisteredSymbolError);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the creation of a normalized subset of a composition.
|
||||
* @details This test creates a composition, finalizes it, and then extracts a subset
|
||||
* containing only one of the original elements. It verifies that the `subset` method with
|
||||
* the "norm" option creates a new, valid composition where the single element's mass
|
||||
* fraction is normalized to 1.0.
|
||||
* @par What this test proves:
|
||||
* - The `subset` method can extract a subset of symbols.
|
||||
* - The "norm" method correctly renormalizes the fractions in the new subset to sum to 1.0.
|
||||
* @par What this test does not prove:
|
||||
* - The behavior of the `subset` method with the "none" option.
|
||||
*/
|
||||
TEST_F(compositionTest, subset) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6);
|
||||
comp.setMassFraction("He-4", 0.4);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
|
||||
std::vector<std::string> symbols = {"H-1"};
|
||||
fourdst::composition::Composition subsetComp = comp.subset(symbols, "norm");
|
||||
EXPECT_TRUE(subsetComp.finalize());
|
||||
EXPECT_DOUBLE_EQ(subsetComp.getMassFraction("H-1"), 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the auto-normalization feature of the `finalize` method.
|
||||
* @details This test sets mass fractions that do not sum to 1.0 and then calls
|
||||
* `finalize(true)`. It verifies that the composition is successfully finalized and that
|
||||
* the mass fractions are correctly scaled to sum to 1.0.
|
||||
* @par What this test proves:
|
||||
* - `finalize(true)` correctly calculates the sum of fractions and normalizes each entry.
|
||||
* - The resulting composition is valid and its normalized values can be retrieved.
|
||||
* @par What this test does not prove:
|
||||
* - The behavior of `finalize(false)`, which is tested separately.
|
||||
*/
|
||||
TEST_F(compositionTest, finalizeWithNormalization) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.3);
|
||||
comp.setMassFraction("He-4", 0.3);
|
||||
EXPECT_TRUE(comp.finalize(true));
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.5);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("He-4"), 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the default (non-normalizing) behavior of the `finalize` method.
|
||||
* @details This test sets mass fractions that already sum to 1.0 and calls `finalize(false)`.
|
||||
* It verifies that the composition is successfully finalized and the fractions remain unchanged.
|
||||
* @par What this test proves:
|
||||
* - `finalize(false)` or `finalize()` correctly validates a pre-normalized composition without altering its values.
|
||||
* @par What this test does not prove:
|
||||
* - That `finalize(false)` would fail for a non-normalized composition (this is implicitly tested in `setGetComposition`).
|
||||
*/
|
||||
TEST_F(compositionTest, finalizeWithoutNormalization) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.5);
|
||||
comp.setMassFraction("He-4", 0.5);
|
||||
EXPECT_TRUE(comp.finalize(false));
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.5);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("He-4"), 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the retrieval of global composition properties.
|
||||
* @details After creating and finalizing a composition, this test retrieves the
|
||||
* `CompositionEntry` and `GlobalComposition` data. It verifies that the mass fraction
|
||||
* in the entry and the calculated global properties (mean particle mass, specific number density)
|
||||
* are correct for the given input composition.
|
||||
* @par What this test proves:
|
||||
* - The `finalize` method correctly computes `meanParticleMass` and `specificNumberDensity`.
|
||||
* - The `getComposition` method returns a pair containing the correct entry-level and global data.
|
||||
* @par What this test does not prove:
|
||||
* - The correctness of these calculations for all possible compositions, particularly complex ones. It validates the mechanism for a simple binary mixture.
|
||||
*/
|
||||
TEST_F(compositionTest, getComposition) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6);
|
||||
comp.setMassFraction("He-4", 0.4);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
|
||||
const auto compositionEntry = comp.getComposition("H-1");
|
||||
EXPECT_DOUBLE_EQ(compositionEntry.first.mass_fraction(), 0.6);
|
||||
EXPECT_DOUBLE_EQ(compositionEntry.second.meanParticleMass, 1.4382769310381101);
|
||||
EXPECT_DOUBLE_EQ(compositionEntry.second.specificNumberDensity, 1.0/1.4382769310381101);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the ability to switch between mass and number fraction modes.
|
||||
* @details This test creates a composition in mass fraction mode, finalizes it, and then
|
||||
* switches to number fraction mode using `setCompositionMode(false)`. It then modifies the
|
||||
* composition using number fractions and verifies that it must be re-finalized before switching back.
|
||||
* @par What this test proves:
|
||||
* - `setCompositionMode` can be called on a finalized composition.
|
||||
* - After switching modes, the appropriate `set...Fraction` method can be used.
|
||||
* - Switching modes requires the composition to be finalized, and modifying it after the switch un-finalizes it again.
|
||||
* @par What this test does not prove:
|
||||
* - The numerical correctness of the fraction conversions that happen internally when the mode is switched.
|
||||
*/
|
||||
TEST_F(compositionTest, setCompositionMode) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6);
|
||||
comp.setMassFraction("He-4", 0.4);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("H-1"), 0.6);
|
||||
EXPECT_DOUBLE_EQ(comp.getMassFraction("He-4"), 0.4);
|
||||
|
||||
EXPECT_NO_THROW(comp.setCompositionMode(false));
|
||||
|
||||
EXPECT_NO_THROW(comp.setNumberFraction("H-1", 0.9));
|
||||
EXPECT_NO_THROW(comp.setNumberFraction("He-4", 0.1));
|
||||
|
||||
EXPECT_THROW(comp.setCompositionMode(true), fourdst::composition::exceptions::CompositionNotFinalizedError);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
EXPECT_NO_THROW(comp.setCompositionMode(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the `hasSymbol` utility method.
|
||||
* @details This test verifies that `hasSymbol` correctly reports the presence of registered
|
||||
* symbols and the absence of non-registered symbols.
|
||||
* @par What this test proves:
|
||||
* - The `hasSymbol` method accurately checks for the existence of a key in the internal composition map.
|
||||
* @par What this test does not prove:
|
||||
* - Anything about the state (e.g., mass fraction) of the symbol, only its presence.
|
||||
*/
|
||||
TEST_F(compositionTest, hasSymbol) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6);
|
||||
comp.setMassFraction("He-4", 0.4);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp.finalize()));
|
||||
|
||||
EXPECT_TRUE(comp.hasSymbol("H-1"));
|
||||
EXPECT_TRUE(comp.hasSymbol("He-4"));
|
||||
EXPECT_FALSE(comp.hasSymbol("H-2"));
|
||||
EXPECT_FALSE(comp.hasSymbol("He-3"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the mixing of two compositions.
|
||||
* @details This test creates two distinct compositions, finalizes them, and then mixes them
|
||||
* using both the `+` operator (50/50 mix) and the `mix` method with a specific fraction (25/75).
|
||||
* It verifies that the resulting mass fractions in the new compositions are correct.
|
||||
* @par What this test proves:
|
||||
* - The `mix` method and the `+` operator correctly perform linear interpolation of mass fractions.
|
||||
* - The resulting mixed composition is valid and its properties are correctly calculated.
|
||||
* @par What this test does not prove:
|
||||
* - The behavior when mixing compositions with non-overlapping sets of symbols.
|
||||
*/
|
||||
TEST_F(compositionTest, mix) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp1;
|
||||
comp1.registerSymbol("H-1");
|
||||
comp1.registerSymbol("He-4");
|
||||
comp1.setMassFraction("H-1", 0.6);
|
||||
comp1.setMassFraction("He-4", 0.4);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp1.finalize()));
|
||||
|
||||
fourdst::composition::Composition comp2;
|
||||
comp2.registerSymbol("H-1");
|
||||
comp2.registerSymbol("He-4");
|
||||
comp2.setMassFraction("H-1", 0.4);
|
||||
comp2.setMassFraction("He-4", 0.6);
|
||||
EXPECT_NO_THROW(static_cast<void>(comp2.finalize()));
|
||||
|
||||
fourdst::composition::Composition mixedComp = comp1 + comp2;
|
||||
EXPECT_TRUE(mixedComp.finalize());
|
||||
EXPECT_DOUBLE_EQ(mixedComp.getMassFraction("H-1"), 0.5);
|
||||
EXPECT_DOUBLE_EQ(mixedComp.getMassFraction("He-4"), 0.5);
|
||||
|
||||
fourdst::composition::Composition mixedComp2 = comp1.mix(comp2, 0.25);
|
||||
EXPECT_TRUE(mixedComp2.finalize());
|
||||
EXPECT_DOUBLE_EQ(mixedComp2.getMassFraction("H-1"), 0.45);
|
||||
EXPECT_DOUBLE_EQ(mixedComp2.getMassFraction("He-4"), 0.55);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests the calculation of molar abundance.
|
||||
* @details This test creates a simple composition and verifies that `getMolarAbundance`
|
||||
* returns the correct value, which is defined as (mass fraction / atomic mass).
|
||||
* @par What this test proves:
|
||||
* - The `getMolarAbundance` calculation is performed correctly.
|
||||
* @par What this test does not prove:
|
||||
* - The correctness of the underlying mass data, which is tested separately.
|
||||
*/
|
||||
TEST_F(compositionTest, molarAbundance) {
|
||||
fourdst::composition::Composition comp1;
|
||||
comp1.registerSymbol("H-1");
|
||||
comp1.registerSymbol("He-4");
|
||||
comp1.setMassFraction("H-1", 0.5);
|
||||
comp1.setMassFraction("He-4", 0.5);
|
||||
const bool didFinalize = comp1.finalize();
|
||||
|
||||
EXPECT_TRUE(didFinalize);
|
||||
EXPECT_DOUBLE_EQ(comp1.getMolarAbundance("H-1"), 0.5/fourdst::atomic::H_1.mass());
|
||||
EXPECT_DOUBLE_EQ(comp1.getMolarAbundance("He-4"), 0.5/fourdst::atomic::He_4.mass());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -421,12 +172,12 @@ TEST_F(compositionTest, molarAbundance) {
|
||||
*/
|
||||
TEST_F(compositionTest, getRegisteredSpecies) {
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSpecies({fourdst::atomic::Be_7, fourdst::atomic::H_1, fourdst::atomic::He_4}, true);
|
||||
comp.registerSpecies({fourdst::atomic::Be_7, fourdst::atomic::H_1, fourdst::atomic::He_4});
|
||||
auto registeredSpecies = comp.getRegisteredSpecies();
|
||||
EXPECT_TRUE(registeredSpecies.contains(fourdst::atomic::H_1));
|
||||
EXPECT_TRUE(registeredSpecies.contains(fourdst::atomic::He_4));
|
||||
EXPECT_FALSE(registeredSpecies.contains(fourdst::atomic::Li_6));
|
||||
auto it1 = registeredSpecies.begin();
|
||||
const auto it1 = registeredSpecies.begin();
|
||||
EXPECT_EQ(*it1, fourdst::atomic::H_1);
|
||||
}
|
||||
|
||||
@@ -444,236 +195,6 @@ TEST_F(compositionTest, getSpeciesFromAZ) {
|
||||
EXPECT_EQ(fourdst::atomic::SpeciesErrorType::ELEMENT_SYMBOL_NOT_FOUND, fourdst::atomic::az_to_species(120, 500).error());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests constructors that take vectors and sets of symbols.
|
||||
* @details This test verifies that the Composition can be constructed from a vector or set of symbols,
|
||||
* and that the resulting object correctly registers those symbols.
|
||||
* @par What this test proves:
|
||||
* - Constructors accepting std::vector and std::set of symbols work as expected.
|
||||
* - Registered symbols are correctly tracked.
|
||||
*/
|
||||
TEST_F(compositionTest, constructorWithSymbolsVectorAndSet) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
std::vector<std::string> vs = {"H-1", "He-4"};
|
||||
std::set<std::string> ss = {"H-1", "He-4"};
|
||||
|
||||
fourdst::composition::Composition compVec(vs);
|
||||
EXPECT_TRUE(compVec.hasSymbol("H-1"));
|
||||
EXPECT_TRUE(compVec.hasSymbol("He-4"));
|
||||
|
||||
fourdst::composition::Composition compSet(ss);
|
||||
EXPECT_TRUE(compSet.hasSymbol("H-1"));
|
||||
EXPECT_TRUE(compSet.hasSymbol("He-4"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests constructors that take symbols and fractions for both mass and number fraction modes.
|
||||
* @details This test verifies that the Composition can be constructed directly from vectors of symbols and fractions,
|
||||
* and that the resulting mass and number fractions are correct. It also checks conversions between modes.
|
||||
* @par What this test proves:
|
||||
* - Constructors for both mass and number fraction modes work as expected.
|
||||
* - Conversion between mass and number fraction modes is correct.
|
||||
*/
|
||||
TEST_F(compositionTest, constructorWithSymbolsAndFractionsMassAndNumber) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
using fourdst::atomic::species;
|
||||
|
||||
// Mass-fraction constructor
|
||||
std::vector<std::string> symM = {"H-1", "He-4"};
|
||||
std::vector<double> fracM = {0.6, 0.4};
|
||||
Composition compM(symM, fracM, true);
|
||||
EXPECT_NEAR(compM.getMassFraction("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(compM.getMassFraction("He-4"), 0.4, 1e-12);
|
||||
// Mean particle mass and specific number density are reciprocals
|
||||
double sn = 0.6/species.at("H-1").mass() + 0.4/species.at("He-4").mass();
|
||||
double mp = 1.0/sn;
|
||||
EXPECT_NEAR(compM.getMeanParticleMass(), mp, 1e-12);
|
||||
|
||||
// Number-fraction constructor
|
||||
std::vector<std::string> symN = {"H-1", "He-4"};
|
||||
std::vector<double> fracN = {0.9, 0.1};
|
||||
Composition compN(symN, fracN, false);
|
||||
EXPECT_NEAR(compN.getNumberFraction("H-1"), 0.9, 1e-12);
|
||||
EXPECT_NEAR(compN.getNumberFraction("He-4"), 0.1, 1e-12);
|
||||
double meanA = 0.9*species.at("H-1").mass() + 0.1*species.at("He-4").mass();
|
||||
EXPECT_NEAR(compN.getMeanParticleMass(), meanA, 1e-12);
|
||||
// Check converted mass fractions X_i = n_i * A_i / <A>
|
||||
double xH = 0.9*species.at("H-1").mass()/meanA;
|
||||
double xHe = 0.1*species.at("He-4").mass()/meanA;
|
||||
compN.setCompositionMode(true);
|
||||
EXPECT_NEAR(compN.getMassFraction("H-1"), xH, 1e-12);
|
||||
EXPECT_NEAR(compN.getMassFraction("He-4"), xHe, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests registering symbols via vector, single Species, and mode mismatch error.
|
||||
* @details This test checks that symbols can be registered via a vector, that registering by Species works,
|
||||
* and that attempting to register a symbol with a mismatched mode throws the correct exception.
|
||||
* @par What this test proves:
|
||||
* - registerSymbol works with vectors.
|
||||
* - registerSpecies works with single Species.
|
||||
* - Mode mismatch throws CompositionModeError.
|
||||
*/
|
||||
TEST_F(compositionTest, registerSymbolVectorAndSingleSpeciesAndModeMismatch) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
Composition comp;
|
||||
comp.registerSymbol(std::vector<std::string>{"H-1", "He-4"});
|
||||
EXPECT_TRUE(comp.hasSymbol("H-1"));
|
||||
EXPECT_TRUE(comp.hasSymbol("He-4"));
|
||||
|
||||
// Register by Species
|
||||
Composition comp2;
|
||||
comp2.registerSpecies(fourdst::atomic::H_1);
|
||||
comp2.registerSpecies(fourdst::atomic::He_4);
|
||||
EXPECT_TRUE(comp2.hasSymbol("H-1"));
|
||||
EXPECT_TRUE(comp2.hasSymbol("He-4"));
|
||||
|
||||
// Mode mismatch should throw
|
||||
Composition comp3;
|
||||
comp3.registerSymbol("H-1", true); // mass mode
|
||||
EXPECT_THROW(comp3.registerSymbol("He-4", false), fourdst::composition::exceptions::CompositionModeError);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests setMassFraction overloads for Species and vectors.
|
||||
* @details This test verifies that setMassFraction works for both single Species and vectors of Species,
|
||||
* and that the returned old values are correct.
|
||||
* @par What this test proves:
|
||||
* - setMassFraction overloads work as expected.
|
||||
* - Old values are returned correctly.
|
||||
*/
|
||||
TEST_F(compositionTest, setMassFractionBySpeciesAndVector) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
using fourdst::atomic::H_1;
|
||||
using fourdst::atomic::He_4;
|
||||
|
||||
Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
|
||||
// Single species overload
|
||||
double old = comp.setMassFraction(H_1, 0.7);
|
||||
EXPECT_NEAR(old, 0.0, 1e-15);
|
||||
old = comp.setMassFraction(He_4, 0.3);
|
||||
EXPECT_NEAR(old, 0.0, 1e-15);
|
||||
|
||||
// Vector overload
|
||||
std::vector<fourdst::atomic::Species> sp = {H_1, He_4};
|
||||
std::vector<double> xs = {0.6, 0.4};
|
||||
auto olds = comp.setMassFraction(sp, xs);
|
||||
ASSERT_EQ(olds.size(), 2u);
|
||||
EXPECT_NEAR(olds[0], 0.7, 1e-12);
|
||||
EXPECT_NEAR(olds[1], 0.3, 1e-12);
|
||||
|
||||
EXPECT_TRUE(comp.finalize());
|
||||
EXPECT_NEAR(comp.getMassFraction("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(comp.getMassFraction(He_4), 0.4, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests setNumberFraction overloads for symbols and Species.
|
||||
* @details This test verifies that setNumberFraction works for both single symbols/Species and vectors,
|
||||
* and that the returned old values are correct.
|
||||
* @par What this test proves:
|
||||
* - setNumberFraction overloads work as expected.
|
||||
* - Old values are returned correctly.
|
||||
*/
|
||||
TEST_F(compositionTest, setNumberFractionOverloads) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
using fourdst::atomic::H_1;
|
||||
using fourdst::atomic::He_4;
|
||||
|
||||
Composition comp;
|
||||
comp.registerSymbol("H-1", false);
|
||||
comp.registerSymbol("He-4", false);
|
||||
|
||||
// Single symbol
|
||||
double old = comp.setNumberFraction("H-1", 0.8);
|
||||
EXPECT_NEAR(old, 0.0, 1e-15);
|
||||
// Vector of symbols
|
||||
auto oldv = comp.setNumberFraction(std::vector<std::string>{"H-1", "He-4"}, std::vector<double>{0.75, 0.25});
|
||||
ASSERT_EQ(oldv.size(), 2u);
|
||||
EXPECT_NEAR(oldv[0], 0.8, 1e-12);
|
||||
EXPECT_NEAR(oldv[1], 0.0, 1e-12);
|
||||
|
||||
// Species and vector<Species>
|
||||
old = comp.setNumberFraction(H_1, 0.7);
|
||||
EXPECT_NEAR(old, 0.75, 1e-12);
|
||||
auto oldsv = comp.setNumberFraction(std::vector<fourdst::atomic::Species>{H_1, He_4}, std::vector<double>{0.6, 0.4});
|
||||
ASSERT_EQ(oldsv.size(), 2u);
|
||||
EXPECT_NEAR(oldsv[0], 0.7, 1e-12);
|
||||
EXPECT_NEAR(oldsv[1], 0.25, 1e-12);
|
||||
|
||||
EXPECT_TRUE(comp.finalize());
|
||||
EXPECT_NEAR(comp.getNumberFraction("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(comp.getNumberFraction(He_4), 0.4, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests error cases for mixing compositions.
|
||||
* @details This test checks that mixing with a non-finalized composition or with invalid fractions throws the correct exceptions.
|
||||
* @par What this test proves:
|
||||
* - Mixing with a non-finalized composition throws CompositionNotFinalizedError.
|
||||
* - Mixing with invalid fractions throws InvalidCompositionError.
|
||||
*/
|
||||
TEST_F(compositionTest, mixErrorCases) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
|
||||
Composition a; a.registerSymbol("H-1"); a.registerSymbol("He-4"); a.setMassFraction("H-1", 0.6); a.setMassFraction("He-4", 0.4);
|
||||
bool didFinalizeA = a.finalize();
|
||||
EXPECT_TRUE(didFinalizeA);
|
||||
Composition b; b.registerSymbol("H-1"); b.registerSymbol("He-4"); b.setMassFraction("H-1", 0.5); b.setMassFraction("He-4", 0.5);
|
||||
// Not finalized second comp
|
||||
EXPECT_THROW(static_cast<void>(a.mix(b, 0.5)), fourdst::composition::exceptions::CompositionNotFinalizedError);
|
||||
bool didFinalizeB = b.finalize();
|
||||
EXPECT_TRUE(didFinalizeB);
|
||||
// Invalid fraction
|
||||
EXPECT_THROW(static_cast<void>(a.mix(b, -0.1)), fourdst::composition::exceptions::InvalidCompositionError);
|
||||
EXPECT_THROW(static_cast<void>(a.mix(b, 1.1)), fourdst::composition::exceptions::InvalidCompositionError);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests getMassFraction and getNumberFraction maps and Species overloads.
|
||||
* @details This test verifies that the getter methods for mass and number fractions return correct maps,
|
||||
* and that overloads for Species work as expected.
|
||||
* @par What this test proves:
|
||||
* - getMassFraction and getNumberFraction return correct maps.
|
||||
* - Overloads for Species work as expected.
|
||||
*/
|
||||
TEST_F(compositionTest, getMassAndNumberFractionMapsAndSpeciesOverloads) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
|
||||
Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6); comp.setMassFraction("He-4", 0.4);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
auto m = comp.getMassFraction();
|
||||
ASSERT_EQ(m.size(), 2u);
|
||||
EXPECT_NEAR(m.at("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(m.at("He-4"), 0.4, 1e-12);
|
||||
EXPECT_NEAR(comp.getMassFraction(fourdst::atomic::H_1), 0.6, 1e-12);
|
||||
EXPECT_NEAR(comp.getMolarAbundance(fourdst::atomic::H_1), m.at("H-1")/fourdst::atomic::H_1.mass(), 1e-12);
|
||||
|
||||
// Switch to number-fraction mode and verify number maps
|
||||
comp.setCompositionMode(false);
|
||||
// Must re-finalize after modifications (mode switch itself keeps values consistent but not finalized status changed? setCompositionMode requires to be finalized; here we just switched modes)
|
||||
// Set specific number fractions and finalize
|
||||
comp.setNumberFraction("H-1", 0.7);
|
||||
comp.setNumberFraction("He-4", 0.3);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
auto n = comp.getNumberFraction();
|
||||
ASSERT_EQ(n.size(), 2u);
|
||||
EXPECT_NEAR(n.at("H-1"), 0.7, 1e-12);
|
||||
EXPECT_NEAR(n.at("He-4"), 0.3, 1e-12);
|
||||
EXPECT_NEAR(comp.getNumberFraction(fourdst::atomic::He_4), 0.3, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests mean atomic number and electron abundance calculations.
|
||||
@@ -682,255 +203,40 @@ TEST_F(compositionTest, getMassAndNumberFractionMapsAndSpeciesOverloads) {
|
||||
* @par What this test proves:
|
||||
* - getElectronAbundance and getMeanAtomicNumber are calculated correctly.
|
||||
*/
|
||||
TEST_F(compositionTest, meanAtomicNumberAndElectronAbundance) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
TEST_F(compositionTest, meanElectronAbundance) {
|
||||
using fourdst::atomic::species;
|
||||
using fourdst::composition::Composition;
|
||||
|
||||
Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6); comp.setMassFraction("He-4", 0.4);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
Composition comp;
|
||||
comp.registerSymbol("H-1");
|
||||
comp.registerSymbol("He-4");
|
||||
|
||||
// Compute expected Ye = sum(X_i * Z_i / A_i)
|
||||
constexpr double xH = 0.6, xHe = 0.4;
|
||||
const double aH = species.at("H-1").a();
|
||||
const double aHe = species.at("He-4").a();
|
||||
const double zH = species.at("H-1").z();
|
||||
const double zHe = species.at("He-4").z();
|
||||
const double expectedYe = xH*zH/aH + xHe*zHe/aHe;
|
||||
comp.setMolarAbundance("H-1", 0.6);
|
||||
comp.setMolarAbundance("He-4", 0.4);
|
||||
|
||||
const double expectedYe = 0.6 * species.at("H-1").z() + 0.4 * species.at("He-4").z();
|
||||
|
||||
EXPECT_NEAR(comp.getElectronAbundance(), expectedYe, 1e-12);
|
||||
|
||||
// <Z> = <A> * sum(X_i * Z_i / A_i)
|
||||
const double expectedZ = comp.getMeanParticleMass() * expectedYe;
|
||||
EXPECT_NEAR(comp.getMeanAtomicNumber(), expectedZ, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests canonical composition and caching behavior.
|
||||
* @details This test verifies that getCanonicalComposition returns correct X, Y, Z values,
|
||||
* and that repeated calls use the cached result.
|
||||
* @par What this test proves:
|
||||
* - getCanonicalComposition returns correct canonical values.
|
||||
* - Caching works as expected.
|
||||
*/
|
||||
TEST_F(compositionTest, canonicalCompositionAndCaching) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
TEST_F(compositionTest, buildFromMassFractions) {
|
||||
using fourdst::atomic::Species;
|
||||
using namespace fourdst::atomic;
|
||||
using fourdst::composition::Composition;
|
||||
|
||||
Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6); comp.setMassFraction("He-4", 0.4);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
const std::vector<Species> sVec = {H_1, He_4, C_12};
|
||||
const std::vector<double> massFractions = {0.7, 0.28, 0.02};
|
||||
|
||||
auto canon1 = comp.getCanonicalComposition();
|
||||
EXPECT_NEAR(canon1.X, 0.6, 1e-12);
|
||||
EXPECT_NEAR(canon1.Y, 0.4, 1e-12);
|
||||
EXPECT_NEAR(canon1.Z, 0.0, 1e-12);
|
||||
const Composition comp = fourdst::composition::buildCompositionFromMassFractions(sVec, massFractions);
|
||||
|
||||
// Call again to exercise caching code path
|
||||
auto canon2 = comp.getCanonicalComposition();
|
||||
EXPECT_NEAR(canon2.X, 0.6, 1e-12);
|
||||
EXPECT_NEAR(canon2.Y, 0.4, 1e-12);
|
||||
EXPECT_NEAR(canon2.Z, 0.0, 1e-12);
|
||||
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);
|
||||
|
||||
// Add a metal and re-check
|
||||
Composition comp2; comp2.registerSymbol("H-1"); comp2.registerSymbol("He-4"); comp2.registerSymbol("O-16");
|
||||
comp2.setMassFraction("H-1", 0.6); comp2.setMassFraction("He-4", 0.35); comp2.setMassFraction("O-16", 0.05);
|
||||
ASSERT_TRUE(comp2.finalize());
|
||||
auto canon3 = comp2.getCanonicalComposition(true);
|
||||
EXPECT_NEAR(canon3.X, 0.6, 1e-12);
|
||||
EXPECT_NEAR(canon3.Y, 0.35, 1e-12);
|
||||
EXPECT_NEAR(canon3.Z, 0.05, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests vector getters, indexing, and species-at-index functionality.
|
||||
* @details This test verifies that the vector getters for mass, number, and molar abundance fractions
|
||||
* return correct values, and that species can be accessed by index.
|
||||
* @par What this test proves:
|
||||
* - Vector getters return correct values.
|
||||
* - Indexing and species-at-index work as expected.
|
||||
*/
|
||||
TEST_F(compositionTest, vectorsAndIndexingAndSpeciesAtIndex) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
using fourdst::atomic::species;
|
||||
|
||||
Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.registerSymbol("O-16");
|
||||
comp.setMassFraction("H-1", 0.5); comp.setMassFraction("He-4", 0.3); comp.setMassFraction("O-16", 0.2);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
// Mass fraction vector sorted by mass: H-1, He-4, O-16
|
||||
auto mv = comp.getMassFractionVector();
|
||||
ASSERT_EQ(mv.size(), 3u);
|
||||
EXPECT_NEAR(mv[0], 0.5, 1e-12);
|
||||
EXPECT_NEAR(mv[1], 0.3, 1e-12);
|
||||
EXPECT_NEAR(mv[2], 0.2, 1e-12);
|
||||
|
||||
// Species indices ordering
|
||||
size_t iH = comp.getSpeciesIndex("H-1");
|
||||
size_t iHe = comp.getSpeciesIndex("He-4");
|
||||
size_t iO = comp.getSpeciesIndex("O-16");
|
||||
EXPECT_LT(iH, iHe);
|
||||
EXPECT_LT(iHe, iO);
|
||||
EXPECT_EQ(comp.getSpeciesIndex(fourdst::atomic::H_1), iH);
|
||||
EXPECT_EQ(comp.getSpeciesIndex(species.at("He-4")), iHe);
|
||||
|
||||
// Species at index
|
||||
auto sAtHe = comp.getSpeciesAtIndex(iHe);
|
||||
EXPECT_EQ(std::string(sAtHe.name()), std::string("He-4"));
|
||||
|
||||
// Number fraction vector after switching modes
|
||||
comp.setCompositionMode(false);
|
||||
// Tweak number fractions and finalize
|
||||
// Compute expected number fractions from original mass fractions first
|
||||
double denom = 0.5/species.at("H-1").mass() + 0.3/species.at("He-4").mass() + 0.2/species.at("O-16").mass();
|
||||
double nH_exp = (0.5/species.at("H-1").mass())/denom;
|
||||
double nHe_exp = (0.3/species.at("He-4").mass())/denom;
|
||||
double nO_exp = (0.2/species.at("O-16").mass())/denom;
|
||||
|
||||
auto nv0 = comp.getNumberFractionVector();
|
||||
ASSERT_EQ(nv0.size(), 3u);
|
||||
EXPECT_NEAR(nv0[iH], nH_exp, 1e-12);
|
||||
EXPECT_NEAR(nv0[iHe], nHe_exp, 1e-12);
|
||||
EXPECT_NEAR(nv0[iO], nO_exp, 1e-12);
|
||||
|
||||
// Molar abundance vector X_i/A_i in mass mode; switch back to mass mode to verify
|
||||
comp.setCompositionMode(true);
|
||||
bool didFinalize = comp.finalize(true);
|
||||
EXPECT_TRUE(didFinalize);
|
||||
auto av = comp.getMolarAbundanceVector();
|
||||
ASSERT_EQ(av.size(), 3u);
|
||||
EXPECT_NEAR(av[iH], 0.5/species.at("H-1").mass(), 1e-12);
|
||||
EXPECT_NEAR(av[iHe], 0.3/species.at("He-4").mass(), 1e-12);
|
||||
EXPECT_NEAR(av[iO], 0.2/species.at("O-16").mass(), 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests contains method and pre-finalization guards.
|
||||
* @details This test verifies that contains throws before finalization and works correctly after.
|
||||
* @par What this test proves:
|
||||
* - contains throws before finalize.
|
||||
* - contains works as expected after finalize.
|
||||
*/
|
||||
TEST_F(compositionTest, containsAndPreFinalizationGuards) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1"); comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6); comp.setMassFraction("He-4", 0.4);
|
||||
// contains should throw before finalize
|
||||
EXPECT_THROW(static_cast<void>(comp.contains(fourdst::atomic::H_1)), fourdst::composition::exceptions::CompositionNotFinalizedError);
|
||||
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
EXPECT_TRUE(comp.contains(fourdst::atomic::H_1));
|
||||
EXPECT_FALSE(comp.contains(fourdst::atomic::Li_6));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests subset method with "none" normalization and normalization flow.
|
||||
* @details This test verifies that subset with "none" does not normalize by default,
|
||||
* and that normalization can be forced with finalize(true).
|
||||
* @par What this test proves:
|
||||
* - subset with "none" does not normalize by default.
|
||||
* - finalize(true) normalizes the subset.
|
||||
*/
|
||||
TEST_F(compositionTest, subsetNoneMethodAndNormalizationFlow) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.registerSymbol("O-16");
|
||||
comp.setMassFraction("H-1", 0.5); comp.setMassFraction("He-4", 0.3); comp.setMassFraction("O-16", 0.2);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
fourdst::composition::Composition sub = comp.subset(std::vector<std::string>{"H-1", "He-4"}, "none");
|
||||
// Not normalized: finalize without normalization should fail
|
||||
EXPECT_FALSE(sub.finalize(false));
|
||||
// With normalization, it should succeed and scale to sum to 1
|
||||
EXPECT_TRUE(sub.finalize(true));
|
||||
double sum = sub.getMassFraction("H-1") + sub.getMassFraction("He-4");
|
||||
EXPECT_NEAR(sum, 1.0, 1e-12);
|
||||
EXPECT_NEAR(sub.getMassFraction("H-1"), 0.5/(0.5+0.3), 1e-12);
|
||||
EXPECT_NEAR(sub.getMassFraction("He-4"), 0.3/(0.5+0.3), 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests copy constructor and assignment operator for independence.
|
||||
* @details This test verifies that copies of a Composition object are independent of the original.
|
||||
* @par What this test proves:
|
||||
* - Copy constructor and assignment operator create independent objects.
|
||||
*/
|
||||
TEST_F(compositionTest, copyConstructorAndAssignmentIndependence) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
|
||||
Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6); comp.setMassFraction("He-4", 0.4);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
Composition copy(comp); // copy ctor
|
||||
EXPECT_NEAR(copy.getMassFraction("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(copy.getMassFraction("He-4"), 0.4, 1e-12);
|
||||
|
||||
Composition assigned; assigned = comp; // assignment
|
||||
EXPECT_NEAR(assigned.getMassFraction("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(assigned.getMassFraction("He-4"), 0.4, 1e-12);
|
||||
|
||||
// Modify original and ensure copies do not change
|
||||
comp.setMassFraction("H-1", 0.7); comp.setMassFraction("He-4", 0.3); ASSERT_TRUE(comp.finalize());
|
||||
EXPECT_NEAR(copy.getMassFraction("H-1"), 0.6, 1e-12);
|
||||
EXPECT_NEAR(assigned.getMassFraction("He-4"), 0.4, 1e-12);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests getComposition by Species and retrieval of all entries.
|
||||
* @details This test verifies that getComposition works for both single Species and all entries,
|
||||
* and that the returned values are correct.
|
||||
* @par What this test proves:
|
||||
* - getComposition works for both single Species and all entries.
|
||||
*/
|
||||
TEST_F(compositionTest, getCompositionBySpeciesAndAllEntries) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
using fourdst::composition::Composition;
|
||||
|
||||
Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4");
|
||||
comp.setMassFraction("H-1", 0.6); comp.setMassFraction("He-4", 0.4);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
auto pairBySpec = comp.getComposition(fourdst::atomic::H_1);
|
||||
EXPECT_NEAR(pairBySpec.first.mass_fraction(), 0.6, 1e-12);
|
||||
EXPECT_NEAR(pairBySpec.second.meanParticleMass, comp.getMeanParticleMass(), 1e-15);
|
||||
|
||||
auto all = comp.getComposition();
|
||||
ASSERT_EQ(all.first.size(), 2u);
|
||||
EXPECT_NEAR(all.first.at("H-1").mass_fraction(), 0.6, 1e-12);
|
||||
EXPECT_NEAR(all.first.at("He-4").mass_fraction(), 0.4, 1e-12);
|
||||
EXPECT_NEAR(all.second.meanParticleMass, comp.getMeanParticleMass(), 1e-15);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests iteration over composition and out-of-range index access.
|
||||
* @details This test verifies that begin/end iteration covers all entries,
|
||||
* and that accessing an out-of-range index throws an exception.
|
||||
* @par What this test proves:
|
||||
* - Iteration covers all entries.
|
||||
* - Out-of-range index throws std::out_of_range.
|
||||
*/
|
||||
TEST_F(compositionTest, iterationBeginEndAndIndexOutOfRange) {
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.registerSymbol("O-16");
|
||||
comp.setMassFraction("H-1", 0.5); comp.setMassFraction("He-4", 0.3); comp.setMassFraction("O-16", 0.2);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
|
||||
// Iterate and count entries
|
||||
size_t count = 0;
|
||||
for (auto it = comp.begin(); it != comp.end(); ++it) {
|
||||
count++;
|
||||
}
|
||||
EXPECT_EQ(count, 3u);
|
||||
|
||||
// Out-of-range access
|
||||
EXPECT_THROW(static_cast<void>(comp.getSpeciesAtIndex(100)), std::out_of_range);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tests inheritance from CompositionAbstract and overriding a getter.
|
||||
@@ -960,15 +266,12 @@ TEST_F(compositionTest, abstractBase) {
|
||||
}
|
||||
};
|
||||
|
||||
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
|
||||
fourdst::composition::Composition comp;
|
||||
comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.registerSymbol("O-16");
|
||||
comp.setMassFraction("H-1", 0.5); comp.setMassFraction("He-4", 0.3); comp.setMassFraction("O-16", 0.2);
|
||||
ASSERT_TRUE(comp.finalize());
|
||||
comp.setMolarAbundance("H-1", 0.6); comp.setMolarAbundance("He-4", 0.6);
|
||||
|
||||
const UnrestrictedComposition uComp(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"));
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user