docs(docs): added robust docs

This commit is contained in:
2025-07-24 09:35:52 -04:00
parent 1905e642ab
commit 9f5ef7fd6a
452 changed files with 578689 additions and 218 deletions

View File

@@ -1,29 +1,87 @@
#pragma once
#include <unordered_map>
#include <string_view>
#include <string>
#include <iostream>
#include <limits>
/**
* @namespace fourdst::atomic
* @brief Contains classes and functions related to atomic data, such as properties of atomic species.
*/
namespace fourdst::atomic {
/**
* @brief Converts a spin-parity string (JPI string) to a double-precision floating-point number.
* @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);
/**
* @struct Species
* @brief Represents an atomic species (isotope) with its fundamental physical properties.
*
* This struct holds data parsed from nuclear data libraries, such as atomic mass,
* half-life, and spin. It is a fundamental data structure for representing the
* components of a material composition.
*
* @note This struct is designed to be lightweight and is primarily a data container.
*
* @par Usage Example
* @code
* #include "fourdst/composition/atomicSpecies.h"
* #include <iostream>
*
* int main() {
* // Create a species for Deuterium (H-2)
* fourdst::atomic::Species deuterium(
* "H2", "H", 1002, 1, 1, 2, 2224.52, "", 0.0, -1.0, "1+", "", 2.0141017781, 4.0e-11
* );
*
* std::cout << "Species: " << deuterium.name() << std::endl;
* std::cout << "Atomic Mass: " << deuterium.mass() << " u" << std::endl;
* std::cout << "Spin: " << deuterium.spin() << std::endl;
*
* return 0;
* }
* @endcode
*/
struct Species {
std::string m_name; //< Name of the species
std::string m_el; //< Element symbol
int m_nz; //< NZ
int m_n; //< N
int m_z; //< Z
int m_a; //< A
double m_bindingEnergy; //< Binding energy
std::string m_betaCode; //< Beta decay code
double m_betaDecayEnergy; //< Beta decay energy
double m_halfLife_s; //< Half-life in seconds
std::string m_spinParity; //< Spin and parity
std::string m_decayModes; //< Decay modes
double m_atomicMass; //< Atomic mass
double m_atomicMassUnc; //< Atomic mass uncertainty
double m_spin = 0.0; //< Spin of the species, default is 0.0
std::string m_name; ///< Name of the species (e.g., "Fe56").
std::string m_el; ///< Element symbol (e.g., "Fe").
int m_nz; ///< NZ identifier, typically 1000*Z + A.
int m_n; ///< Number of neutrons.
int m_z; ///< Atomic number (number of protons).
int m_a; ///< Mass number (N + Z).
double m_bindingEnergy; ///< Binding energy in keV.
std::string m_betaCode; ///< Beta decay code.
double m_betaDecayEnergy; ///< Beta decay energy in keV.
double m_halfLife_s; ///< Half-life in seconds. A value of -1.0 typically indicates stability.
std::string m_spinParity; ///< Spin and parity as a string (e.g., "1/2-").
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.
/**
* @brief Constructs a Species object with detailed properties.
*
* @param name Name of the species.
* @param el Element symbol.
* @param nz NZ identifier.
* @param n Number of neutrons.
* @param z Atomic number.
* @param a Mass number.
* @param bindingEnergy Binding energy.
* @param betaCode Beta decay code.
* @param betaDecayEnergy Beta decay energy.
* @param halfLife_s Half-life in seconds.
* @param spinParity Spin and parity string.
* @param decayModes Decay modes string.
* @param atomicMass Atomic mass.
* @param atomicMassUnc Atomic mass uncertainty.
*
* @post The `m_spin` member is initialized by parsing `m_spinParity` using `convert_jpi_to_double`.
*/
Species(
const std::string_view name,
const std::string_view el,
@@ -57,7 +115,11 @@ namespace fourdst::atomic {
m_spin = convert_jpi_to_double(m_spinParity);
};
//Copy constructor
/**
* @brief Copy constructor for Species.
* @param species The Species object to copy.
* @post A new Species object is created as a deep copy of `species`. The `m_spin` member is re-calculated.
*/
Species(const Species& species) {
m_name = species.m_name;
m_el = species.m_el;
@@ -77,66 +139,132 @@ namespace fourdst::atomic {
}
/**
* @brief Gets the atomic mass of the species.
* @return The atomic mass in atomic mass units (u).
*/
[[nodiscard]] double mass() const {
return m_atomicMass;
}
/**
* @brief Gets the uncertainty in the atomic mass.
* @return The atomic mass uncertainty.
*/
[[nodiscard]] double massUnc() const {
return m_atomicMassUnc;
}
/**
* @brief Gets the half-life of the species.
* @return The half-life in seconds.
*/
[[nodiscard]] double halfLife() const {
return m_halfLife_s;
}
/**
* @brief Gets the spin and parity as a string.
* @return A string_view of the spin and parity (e.g., "1/2+").
*/
[[nodiscard]] std::string_view spinParity() const {
return m_spinParity;
}
/**
* @brief Gets the decay modes as a string.
* @return A string_view of the decay modes.
*/
[[nodiscard]] std::string_view decayModes() const {
return m_decayModes;
}
/**
* @brief Gets the binding energy of the species.
* @return The binding energy in keV.
*/
[[nodiscard]] double bindingEnergy() const {
return m_bindingEnergy;
}
/**
* @brief Gets the beta decay energy of the species.
* @return The beta decay energy in keV.
*/
[[nodiscard]] double betaDecayEnergy() const {
return m_betaDecayEnergy;
}
/**
* @brief Gets the beta decay code.
* @return A string_view of the beta decay code.
*/
[[nodiscard]] std::string_view betaCode() const {
return m_betaCode;
}
/**
* @brief Gets the name of the species.
* @return A string_view of the species name (e.g., "Fe56").
*/
[[nodiscard]] std::string_view name() const {
return m_name;
}
/**
* @brief Gets the element symbol of the species.
* @return A string_view of the element symbol (e.g., "Fe").
*/
[[nodiscard]] std::string_view el() const {
return m_el;
}
/**
* @brief Gets the NZ identifier of the species.
* @return The NZ identifier (1000*Z + A).
*/
[[nodiscard]] int nz() const {
return m_nz;
}
/**
* @brief Gets the number of neutrons.
* @return The number of neutrons (N).
*/
[[nodiscard]] int n() const {
return m_n;
}
/**
* @brief Gets the atomic number (number of protons).
* @return The atomic number (Z).
*/
[[nodiscard]] int z() const {
return m_z;
}
/**
* @brief Gets the mass number.
* @return The mass number (A = N + Z).
*/
[[nodiscard]] int a() const {
return m_a;
}
/**
* @brief Gets the nuclear spin as a numeric value.
* @return The spin as a double.
*/
[[nodiscard]] double spin() const {
return m_spin;
}
/**
* @brief Overloads the stream insertion operator for easy printing of a Species object.
* @param os The output stream.
* @param species The Species object to print.
* @return The output stream with the species name.
*/
friend std::ostream& operator<<(std::ostream& os, const Species& species) {
os << species.m_name;
return os;
@@ -147,19 +275,73 @@ namespace fourdst::atomic {
friend bool operator<(const Species& lhs, const Species& rhs);
friend bool operator>(const Species& lhs, const Species& rhs);
};
/**
* @brief Equality operator for Species. Compares based on name.
* @param lhs The left-hand side Species.
* @param rhs The right-hand side Species.
* @return `true` if the names are identical, `false` otherwise.
*/
inline bool operator==(const Species& lhs, const Species& rhs) {
return (lhs.m_name == rhs.m_name);
}
/**
* @brief Inequality operator for Species. Compares based on name.
* @param lhs The left-hand side Species.
* @param rhs The right-hand side Species.
* @return `true` if the names are different, `false` otherwise.
*/
inline bool operator!=(const Species& lhs, const Species& rhs) {
return (lhs.m_name != rhs.m_name);
}
/**
* @brief Less-than operator for Species. Compares based on atomic mass.
* @param lhs The left-hand side Species.
* @param rhs The right-hand side Species.
* @return `true` if lhs atomic mass is less than rhs atomic mass, `false` otherwise.
*/
inline bool operator<(const Species& lhs, const Species& rhs) {
return (lhs.m_atomicMass < rhs.m_atomicMass);
}
/**
* @brief Greater-than operator for Species. Compares based on atomic mass.
* @param lhs The left-hand side Species.
* @param rhs The right-hand side Species.
* @return `true` if lhs atomic mass is greater than rhs atomic mass, `false` otherwise.
*/
inline bool operator>(const Species& lhs, const Species& rhs) {
return (lhs.m_atomicMass > rhs.m_atomicMass);
}
/**
* @brief Converts a spin-parity string (JPI string) to a double-precision floating-point number representing the spin.
*
* @details
* **Purpose and Usage:**
* This function is a utility for converting the textual representation of nuclear spin and parity,
* commonly found in nuclear data files (e.g., "5/2-"), into a numerical format (`double`)
* that can be used in calculations. It is used internally by the `Species` constructor to
* initialize the `m_spin` member.
*
* **Algorithm:**
* The function robustly parses various formats of JPI strings:
* 1. **Sanitization:** It first removes common non-numeric characters like `(`, `)`, `*`, and `#`.
* 2. **Parity-Only:** Strings containing only `+` or `-` are treated as spin 0.
* 3. **Comma-Separated:** If multiple values are present (e.g., "3/2+,5/2+"), it considers only the first one.
* 4. **Parity Suffix:** It removes the trailing `+` or `-` parity indicator.
* 5. **Fractional vs. Integer:**
* - If the string contains a `/` (e.g., "5/2"), it parses the numerator and denominator to calculate the fraction.
* - Otherwise, it attempts to parse the string directly as a double (for integer spins like "1", "2").
* 6. **Error Handling:** If the string is empty, malformed, or results in division by zero,
* it returns `std::numeric_limits<double>::quiet_NaN()` to indicate a parsing failure.
* This function does not throw exceptions but relies on the return value for error signaling.
*
* @param jpi_string The spin-parity string to convert.
*
* @pre The input `jpi_string` is a standard C++ string.
* @post The function returns a `double` representing the spin, or `NaN` if parsing fails. The input string is not modified.
*
* @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) {
std::string s = jpi_string;
@@ -216,8 +398,36 @@ namespace fourdst::atomic {
}
/**
* @brief Specialization of `std::hash` for `fourdst::atomic::Species`.
*
* @details
* This allows `fourdst::atomic::Species` objects to be used as keys in unordered
* associative containers like `std::unordered_map` and `std::unordered_set`.
* The hash is computed based on the species' name (`m_name`), as it is expected
* to be a unique identifier for each species.
*
* @par Usage Example
* @code
* #include "fourdst/composition/atomicSpecies.h"
* #include <unordered_map>
* #include <string>
*
* int main() {
* std::unordered_map<fourdst::atomic::Species, double> abundance;
* fourdst::atomic::Species h1("H1", ...);
* abundance[h1] = 0.999;
* return 0;
* }
* @endcode
*/
template<>
struct std::hash<fourdst::atomic::Species> {
/**
* @brief Computes the hash for a Species object.
* @param s The Species object to hash.
* @return The hash value of the species' name.
*/
size_t operator()(const fourdst::atomic::Species& s) const noexcept {
return std::hash<std::string>()(s.m_name);
}

View File

@@ -31,11 +31,26 @@
#include "fourdst/composition/atomicSpecies.h"
namespace fourdst::composition {
/**
* @struct CanonicalComposition
* @brief Represents the canonical (X, Y, Z) composition of stellar material.
* @details This is a standard astrophysical representation where:
* - X is the total mass fraction of all hydrogen isotopes.
* - Y is the total mass fraction of all helium isotopes.
* - Z is the total mass fraction of all other elements (metals).
* By definition, X + Y + Z should sum to 1.0.
*/
struct CanonicalComposition {
double X = 0.0; ///< Mass fraction of Hydrogen.
double Y = 0.0; ///< Mass fraction of Helium.
double Z = 0.0; ///< Mass fraction of Metals.
/**
* @brief Overloads the stream insertion operator for easy printing.
* @param os The output stream.
* @param composition The CanonicalComposition object to print.
* @return The output stream.
*/
friend std::ostream& operator<<(std::ostream& os, const CanonicalComposition& composition) {
os << "<CanonicalComposition: "
<< "X = " << composition.X << ", "
@@ -46,42 +61,50 @@ namespace fourdst::composition {
};
/**
* @brief Represents the global composition of a system. This tends to be used after finalize and is primarily for internal use.
* @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 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 meanParticleMass; ///< 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).
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 an entry in the composition with a symbol and mass fraction.
* @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::string m_symbol; ///< The chemical symbol of the species.
atomic::Species m_isotope; ///< The isotope of the species.
bool m_massFracMode = true; ///< The mode of the composition entry. True if mass fraction, false if number fraction.
std::string m_symbol; ///< The chemical symbol of the species (e.g., "H-1", "Fe-56").
atomic::Species m_isotope; ///< 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.
double m_numberFraction = 0.0; ///< The number fraction of the species.
double m_relAbundance = 0.0; ///< The relative abundance of the species for converting between mass and number fractions.
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.
bool m_initialized = false; ///< True if the composition entry has been initialized.
bool m_initialized = false; ///< True if the composition entry has been initialized with a valid species.
/**
* @brief Default constructor.
* @brief Default constructor. Initializes a default entry (H-1), but in an uninitialized state.
*/
CompositionEntry();
/**
* @brief Constructs a CompositionEntry with the given symbol and mode.
* @param symbol The chemical symbol of the species.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* *Example Usage:*
* @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", true);
* CompositionEntry entry("H-1", true); // Entry for H-1 in mass fraction mode.
* @endcode
*/
explicit CompositionEntry(const std::string& symbol, bool massFracMode=true);
@@ -93,83 +116,93 @@ namespace fourdst::composition {
CompositionEntry(const CompositionEntry& entry);
/**
* @brief Sets the species for the composition 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 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 mass fraction of the species given the mean molar mass.
* @param meanMolarMass The mean molar mass.
* @brief Gets the mass fraction, converting from number fraction if necessary.
* @param meanMolarMass The mean molar mass of the entire composition, required for conversion.
* @return The mass fraction of the species.
*/
[[nodiscard]] double mass_fraction(double meanMolarMass) 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 of the species given the total moles.
* @param totalMoles The total moles.
* @brief Gets the number fraction, converting from mass fraction if necessary.
* @param totalMoles 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 totalMoles) const;
/**
* @brief Gets the relative abundance of the species.
* @return The relative abundance of the species.
* @return The relative abundance.
*/
[[nodiscard]] double rel_abundance() const;
/**
* @brief Gets the isotope of the species.
* @return The isotope of the species.
* @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 mass fraction mode, false if number fraction mode.
* @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.
* @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.
* @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 Sets the mode to mass fraction mode.
* @param meanMolarMass The mean molar mass.
* @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 Sets the mode to number fraction mode.
* @param totalMoles The total moles.
* @brief Switches the mode to number fraction mode.
* @param totalMoles 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 totalMoles);
@@ -184,31 +217,42 @@ namespace fourdst::composition {
};
/**
* @brief Manages the composition of elements.
* @details The composition is a collection of elements with their respective mass fractions.
* The general purpose of this class is to provide a standardized interface for managing the composition of
* any part of 4DSSE. There are a few rules when using this class.
* - Only species in the atomicSpecies.h database can be used. There are 1000s (All species from AME2020) in there so it should not be a problem.
* - Before a mass fraction can be set with a particular instance of Composition, the symbol must be registered. (i.e. register He-3 before setting its mass fraction)
* - Before any composition information can be retrieved (e.g. getComposition), the composition must be finalized (call to .finalize()). This checks if the total mass fraction sums to approximately 1 (within 1 part in 10^8)
* - Any changes made to the composition after finalization will "un-finalize" the composition. This means that the composition must be finalized again before any information can be retrieved.
* - The mass fraction of any individual species must be no more than 1 and no less than 0.
* - The only exception to the finalize rule is if the composition was constructed with symbols and mass fractions at instantiation time. In this case, the composition is automatically finalized.
* however, this means that the composition passed to the constructor must be valid.
*
* *Example Usage:* Constructing a finalized composition with symbols and mass fractions:
* @class Composition
* @brief Manages a collection of chemical species and their abundances.
* @details This class is a primary interface for defining and manipulating material compositions.
* It can operate in two modes: mass fraction or number fraction.
*
* **Key Rules and Workflow:**
* 1. **Registration:** Before setting an abundance for a species, its symbol (e.g., "He-4") must be registered using `registerSymbol()` or `registerSpecies()`. All registered species must conform to the same abundance mode (mass or number fraction).
* 2. **Setting Abundances:** Use `setMassFraction()` or `setNumberFraction()` to define the composition.
* 3. **Finalization:** Before querying any compositional data (e.g., `getMassFraction()`, `getMeanParticleMass()`), the composition must be **finalized** by calling `finalize()`. This step validates the composition (abundances sum to ~1.0) and computes global properties.
* 4. **Modification:** Any modification to abundances after finalization will un-finalize the composition, requiring another call to `finalize()` before data can be retrieved again.
* 5. **Construction:** A pre-finalized composition can be created by providing symbols and valid, normalized abundances to the constructor.
*
* @throws This class throws various exceptions from `fourdst::composition::exceptions` for invalid operations, such as using unregistered symbols, providing invalid abundances, or accessing data from a non-finalized composition.
*
* @par Mass Fraction Example:
* @code
* std::vector<std::string> symbols = {"H", "He"};
* std::vector<double> mass_fractions = {0.7, 0.3};
* Composition comp(symbols, mass_fractions);
* Composition comp;
* comp.registerSymbol("H-1");
* comp.registerSymbol("He-4");
* comp.setMassFraction("H-1", 0.75);
* comp.setMassFraction("He-4", 0.25);
* if (comp.finalize()) {
* double he_mass_frac = comp.getMassFraction("He-4"); // Returns 0.25
* }
* @endcode
* *Example Usage:* Constructing a composition with symbols and finalizing it later:
*
* @par Number Fraction Example:
* @code
* std::vector<std::string> symbols = {"H", "He"};
* Composition comp(symbols);
* comp.setComposition("H", 0.7);
* comp.setComposition("He", 0.3);
* comp.finalize();
* Composition comp;
* comp.registerSymbol("H-1", false); // Register in number fraction mode
* comp.registerSymbol("He-4", false);
* comp.setNumberFraction("H-1", 0.9);
* comp.setNumberFraction("He-4", 0.1);
* if (comp.finalize()) {
* double he_num_frac = comp.getNumberFraction("He-4"); // Returns 0.1
* }
* @endcode
*/
class Composition {
@@ -226,24 +270,23 @@ namespace fourdst::composition {
std::unordered_map<std::string, CompositionEntry> m_compositions; ///< The compositions.
/**
* @brief Checks if the given symbol is valid.
* @details A symbol is valid if it is in the atomic species database (species in atomicSpecies.h). These include all the isotopes from AME2020.
* @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 mass fractions are valid.
* @param fractions The mass fractions to check.
* @return True if the mass fractions are valid, false otherwise.
* @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]] bool isValidComposition(const std::vector<double>& fractions) const;
/**
* @brief Validates the given mass fractions.
* @param fractions The mass fractions to validate.
* @throws std::invalid_argument if the mass fractions are invalid.
* @brief Validates the given fractions, throwing an exception on failure.
* @param fractions The fractions to validate.
* @throws exceptions::InvalidCompositionError if the fractions are invalid.
*/
void validateComposition(const std::vector<double>& fractions) const;
@@ -273,47 +316,59 @@ namespace fourdst::composition {
~Composition() = default;
/**
* @brief Finalizes the composition.
* @param norm If true, the composition will be normalized to sum to 1 [Default False]
* @return True if the composition is successfully finalized, false otherwise.
* @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.
*/
bool finalize(bool norm=false);
/**
* @brief Constructs a Composition with the given symbols.
* @param symbols The symbols to initialize the composition with.
* *Example Usage:*
* @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.
* @throws exceptions::InvalidSymbolError if any symbol is invalid.
* @par Usage Example:
* @code
* std::vector<std::string> symbols = {"H", "O"};
* std::vector<std::string> symbols = {"H-1", "O-16"};
* Composition comp(symbols);
* comp.setMassFraction("H-1", 0.11);
* comp.setMassFraction("O-16", 0.89);
* comp.finalize();
* @endcode
*/
explicit Composition(const std::vector<std::string>& symbols);
/**
* @brief Constructs a Composition with the given symbols as a set.
* @param symbols The symbols to initialize the composition with.
* *Example Usage:*
* @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.
* @throws exceptions::InvalidSymbolError if any symbol is invalid.
* @par Usage Example:
* @code
* std::set<std::string> symbols = {"H", "O"};
* std::set<std::string> symbols = {"H-1", "O-16"};
* Composition comp(symbols);
* @endcode
*/
explicit Composition(const std::set<std::string>& symbols);
/**
* @brief Constructs a Composition with the given symbols and mass fractions.
* @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 mass fractions corresponding to the symbols.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* *Example Usage:*
* @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]
* @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.
* @par Usage Example:
* @code
* std::vector<std::string> symbols = {"H", "O"};
* std::vector<double> mass_fractions = {0.1, 0.9};
* Composition comp(symbols, mass_fractions);
* std::vector<std::string> symbols = {"H-1", "O-16"};
* std::vector<double> mass_fractions = {0.1119, 0.8881};
* Composition comp(symbols, mass_fractions); // Finalized on construction
* @endcode
*
* @note The mass fractions must be pre normalized (i.e. by the caller) otherwise this constructor will fail.
*/
Composition(const std::vector<std::string>& symbols, const std::vector<double>& fractions, bool massFracMode=true);
@@ -323,16 +378,25 @@ namespace fourdst::composition {
*/
Composition(const Composition& composition);
/**
* @brief Assignment operator.
* @param other The Composition to assign from.
* @return A reference to this Composition.
*/
Composition& operator=(Composition const& other);
/**
* @brief Registers a new symbol.
* @param symbol The symbol to register.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* *Example Usage:*
* @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:
* @code
* Composition comp;
* comp.registerSymbol("H");
* comp.registerSymbol("H-1"); // Now in mass fraction mode
* comp.registerSymbol("He-4"); // Must also be mass fraction mode
* @endcode
*/
void registerSymbol(const std::string& symbol, bool massFracMode=true);
@@ -340,10 +404,12 @@ namespace fourdst::composition {
/**
* @brief Registers multiple new symbols.
* @param symbols The symbols to register.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* *Example Usage:*
* @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:
* @code
* std::vector<std::string> symbols = {"H", "O"};
* std::vector<std::string> symbols = {"H-1", "O-16"};
* Composition comp;
* comp.registerSymbol(symbols);
* @endcode
@@ -351,33 +417,34 @@ namespace fourdst::composition {
void registerSymbol(const std::vector<std::string>& symbols, bool massFracMode=true);
/**
* @brief Register a new species (will extract the symbol from the species).
* @brief Registers a new species by extracting its symbol.
* @param species The species to register.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* *Example Usage:*
* @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:
* @code
* #include "fourdst/atomic/species.h"
*
* #include "fourdst/composition/species.h" // Assuming species like H1 are defined here
* Composition comp;
* comp.registerSpecies(H_1);
*
* #@endcode
* comp.registerSpecies(fourdst::atomic::species.at("H-1"));
* @endcode
*/
void registerSpecies(const fourdst::atomic::Species& species, bool massFracMode=true);
/**
* @brief Register a vector of new species (will extract the symbol from the species).
* @brief Registers a vector of new species.
* @param species The vector of species to register.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* *Example Usage:*
* @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:
* @code
* #include "fourdst/atomic/species.h"
*
* #include "fourdst/composition/species.h"
* Composition comp;
* comp.registerSpecies({H_1, He_4, O_16}, false); // Will now be in number fraction mode.
*
* #@endcode
* std::vector<fourdst::atomic::Species> my_species = { ... };
* comp.registerSpecies(my_species, false); // Number fraction mode
* @endcode
*/
void registerSpecies(const std::vector<fourdst::atomic::Species>& species, bool massFracMode=true);
@@ -390,46 +457,47 @@ namespace fourdst::composition {
/**
* @brief Get a set of all species that are registered in the composition.
* @return 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;
/**
* @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.
* @return The mass fraction that was set.
* *Example Usage:*
* @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.setMassFraction("H", 0.1);
* 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 fraction for.
* @param symbols The symbols to set the mass fractions for.
* @param mass_fractions The mass fractions corresponding to the symbols.
* @return A vector of mass fractions that were set.
* *Example Usage:*
* @code
* std::vector<std::string> symbols = {"H", "O"};
* std::vector<double> mass_fractions = {0.1, 0.9};
* Composition comp;
* comp.setMassFraction(symbols, mass_fractions);
* @endcode
* @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 Species to set the mass fraction for.
* @param mass_fraction Mass fraction to set for the 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 std::runtime_error if the species is not registered or if the composition is in number fraction mode.
* @throws std::logic_error if the mass fraction is not between 0 and 1.
* @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);
@@ -437,26 +505,30 @@ namespace fourdst::composition {
* @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 mass fractions that were set.
*
* @throws std::runtime_error if the species are not registered or if the composition is in number fraction mode.
* @throws std::logic_error if any mass fraction is not between 0 and 1.
* @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.
* @return The number fraction that was set.
* @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 fraction for.
* @param symbols The symbols to set the number fractions for.
* @param number_fractions The number fractions corresponding to the symbols.
* @return A vector of number fractions that were set.
* @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);
@@ -465,9 +537,9 @@ namespace fourdst::composition {
* @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 std::runtime_error if the species is not registered or if the composition is in mass fraction mode.
* @throws std::logic_error if the number fraction is not between 0 and 1.
* @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);
@@ -475,137 +547,190 @@ namespace fourdst::composition {
* @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 number fractions that were set.
*
* @throws std::runtime_error if the species are not registered or if the composition is in mass fraction mode.
* @throws std::logic_error if any number fraction is not between 0 and 1.
* @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 Mix two compositions together with a given fraction.
* @param other The other composition to mix with.
* @param fraction The fraction of the other composition to mix with. This is the fraction of the other composition wrt. to the current. i.e. fraction=1 would mean that 50% of the new composition is from the other and 50% from the current.
*/
/**
* @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;
/**
* @brief Gets the mass fractions of all compositions.
* @return An unordered map of compositions with their mass fractions.
* @brief Gets the mass fractions of all species in the composition.
* @pre The composition must be finalized.
* @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;
/**
* @brief Gets the mass fraction for a given symbol.
* @pre The composition must be finalized.
* @param symbol The symbol to get the mass fraction for.
* @return The mass fraction 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]] double getMassFraction(const std::string& symbol) const;
/**
* @brief Gets the mass fraction for a given isotope.
* @pre The composition must be finalized.
* @param species The isotope to get the mass fraction for.
* @return The mass fraction for the given isotope.
*
* @throws std::runtime_error if the isotope is not registered in the composition.
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
* @throws exceptions::UnregisteredSymbolError if the isotope is not registered in the composition.
*/
[[nodiscard]] double getMassFraction(const fourdst::atomic::Species& species) const;
/**
* @brief Gets the number fraction for a given symbol.
* @pre The composition must be finalized.
* @param symbol The symbol to get the number fraction for.
* @return The number fraction 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]] double getNumberFraction(const std::string& symbol) const;
/**
* @brief Gets the number fraction for a given isotope.
* @pre The composition must be finalized.
* @param species The isotope to get the number fraction for.
* @return The number fraction for the given isotope.
*
* @throws std::runtime_error if the isotope is not registered in the composition.
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
* @throws exceptions::UnregisteredSymbolError if the isotope is not registered in the composition.
*/
[[nodiscard]] double getNumberFraction(const fourdst::atomic::Species& species) const;
/**
* @brief Gets the number fractions of all compositions.
* @return An unordered map of compositions with their number fractions.
* @brief Gets the number fractions of all species in the composition.
* @pre The composition must be finalized.
* @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;
/**
* @brief Gets the molar abundance for a given symbol.
* @brief Gets the molar abundance (X_i / A_i) for a given symbol.
* @pre The composition must be finalized.
* @param symbol The symbol to get the molar abundance for.
* @return The molar abundance 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]] double getMolarAbundance(const std::string& symbol) const;
/**
* @brief Gets the molar abundance for a given isotope.
* @pre The composition must be finalized.
* @param species The isotope to get the molar abundance for.
* @return The molar abundance for the given isotope.
*
* @throws std::runtime_error if the isotope is not registered in the 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;
/**
* @brief Gets the composition entry and global composition for a given symbol.
* @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.
* @return A pair containing an unordered map of CompositionEntries and the GlobalComposition.
* @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;
/**
* @brief Compute the mean particle mass of the composition.
* @return Mean particle mass in g.
* @pre The composition must be finalized.
* @return Mean particle mass in atomic mass units (g/mol).
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
*/
[[nodiscard]] double getMeanParticleMass() const;
/**
* @brief Compute the mean atomic mass number of the composition.
* @return Mean atomic mass number.
* @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;
/**
* @brief Gets a subset of the composition.
* @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 to use for the subset (default is "norm").
* @return A Composition object containing 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 Check if a symbol is registered.
* @param symbol The symbol to check.
* @return True if the symbol is registered, false otherwise.
*/
/**
* @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;
/**
* @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 fourdst::atomic::Species& isotope) const;
/**
* @brief Sets the composition mode.
* @param massFracMode True if mass fraction mode, false if number fraction mode.
* @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).
* @param harsh If true, this will throw an error if X-Y != Z where Z is computed as the sum of all other elements.
* @return True if mass fraction mode, false if number fraction mode.
*
* @throws std::runtime_error if the composition is not finalized or if the canonical composition cannot be computed.
* @throws std::runtime_error if harsh is true and the canonical composition is not valid.
* @details Calculates the total mass fractions for H, He, and metals.
* @pre The composition must be finalized.
* @param harsh If true, this will throw an error if `1 - (X + Y)` is not equal to the directly summed `Z` (within a tolerance). If false, it will only log a warning.
* @return The `CanonicalComposition` struct.
* @throws exceptions::CompositionNotFinalizedError if the composition is not finalized.
* @throws std::runtime_error if `harsh` is true and the canonical composition is not self-consistent.
*/
[[nodiscard]] CanonicalComposition getCanonicalComposition(bool harsh=false) const;
@@ -617,26 +742,44 @@ namespace fourdst::composition {
*/
friend std::ostream& operator<<(std::ostream& os, const Composition& composition);
// Overload the + operator to call mix with a fraction of 0.5
/**
* @brief Overloads the + operator to mix two compositions together with a fraction of 0.5.
* @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 mixed composition.
* @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();
}
/**
* @brief Returns a const iterator to the beginning of the composition map.
* @return A const iterator to the beginning.
*/
auto begin() const {
return m_compositions.cbegin();
}
/**
* @brief Returns an iterator to the end of the composition map.
* @return An iterator to the end.
*/
auto end() {
return m_compositions.end();
}
/**
* @brief Returns a const iterator to the end of the composition map.
* @return A const iterator to the end.
*/
auto end() const {
return m_compositions.cend();
}

View File

@@ -2,65 +2,146 @@
#include <exception>
#include <string>
#include <iostream>
namespace fourdst::composition::exceptions {
/**
* @class CompositionError
* @brief Base class for exceptions related to composition objects.
*
* This exception is thrown when an error occurs at the composition level,
* such as invalid configuration or state.
*/
class CompositionError : public std::exception {
protected:
/**
* @brief The error message.
*/
std::string m_message;
public:
/**
* @brief Constructs a CompositionError with an error message.
* @param message The error message.
*/
explicit CompositionError(const std::string& message)
: m_message(std::move(message)) {}
/**
* @brief Returns the error message.
* @return A C-style string containing the error message.
*/
const char* what() const noexcept override{
return m_message.c_str();
}
};
/**
* @class CompositionEntryError
* @brief Base class for exceptions related to individual entries within a composition.
*
* This exception is thrown for errors specific to a single component or entry
* in a composition, such as an invalid species symbol or duplicate initialization.
*/
class CompositionEntryError : public std::exception {
protected:
/**
* @brief The error message.
*/
std::string m_message;
public:
/**
* @brief Constructs a CompositionEntryError with an error message.
* @param message The error message.
*/
explicit CompositionEntryError(const std::string& message)
: m_message(std::move(message)) {}
/**
* @brief Returns the error message.
* @return A C-style string containing the error message.
*/
const char* what() const noexcept override {
return m_message.c_str();
}
};
/**
* @class CompositionNotFinalizedError
* @brief Exception thrown when an operation is attempted on a composition that has not been finalized.
*
* Certain operations require the composition to be in a "finalized" state.
* This error indicates that such an operation was called prematurely.
*/
class CompositionNotFinalizedError final : public CompositionError {
using CompositionError::CompositionError;
};
/**
* @class InvalidCompositionError
* @brief Exception thrown when a composition is in an invalid or inconsistent state.
*/
class InvalidCompositionError final : public CompositionError {
using CompositionError::CompositionError;
};
/**
* @class InvalidMixingMode
* @brief Exception thrown for an invalid or unsupported mixing mode.
*
* Compositions can be defined with different mixing modes (e.g., by mass, by mole).
* This error is thrown if an invalid mode is specified.
*/
class InvalidMixingMode final : public CompositionError {
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.
*
* This typically occurs when a chemical species is used that is not known to the system.
*/
class UnregisteredSymbolError final : public CompositionError {
using CompositionError::CompositionError;
};
/**
* @class FailedToFinalizeCompositionError
* @brief Exception thrown when the finalization process of a composition fails.
*/
class FailedToFinalizeCompositionError final : public CompositionError {
using CompositionError::CompositionError;
};
/**
* @class InvalidSpeciesSymbolError
* @brief Exception thrown for an invalid chemical species symbol in a composition entry.
*/
class InvalidSpeciesSymbolError final : public CompositionEntryError {
using CompositionEntryError::CompositionEntryError;
};
/**
* @class EntryAlreadyInitializedError
* @brief Exception thrown when attempting to initialize a composition entry that has already been initialized.
*/
class EntryAlreadyInitializedError final : public CompositionEntryError {
using CompositionEntryError::CompositionEntryError;
};
/**
* @class CompositionModeError
* @brief Exception thrown due to a conflict in composition modes at the entry level.
*
* This may occur if an entry's configuration is incompatible with the overall composition's mode.
*/
class CompositionModeError final : public CompositionEntryError {
using CompositionEntryError::CompositionEntryError;
};

View File

@@ -1,3 +1,15 @@
// ============================================================================
// This file contains the registration of atomic species used in the 4DSTAR
// composition module. Each species is defined as a constant instance of the
// Species class, providing nuclear and atomic properties for use in
// simulations and calculations.
//
// NOTE: This file is automatically generated by utils/atomic/format.py.
// For details on how to regenerate this file, see the README in the
// utils/atomic/ directory.
//
// Do not edit this file manually; changes will be overwritten.
// ============================================================================
#pragma once
#include <unordered_map>
#include <string_view>

View File

@@ -31,7 +31,6 @@
#include "fourdst/composition/atomicSpecies.h"
#include "fourdst/composition/species.h"
#include "fourdst/composition/composition.h"
#include "fourdst/constants/const.h"
#include "fourdst/composition/exceptions/exceptions_composition.h"
namespace fourdst::composition {
@@ -39,7 +38,7 @@ namespace fourdst::composition {
CompositionEntry::CompositionEntry() :
m_symbol("H-1"),
m_isotope(fourdst::atomic::species.at("H-1")),
m_initialized(false) {}
m_initialized(false) {} // Note: Default entry is uninitialized, must be explicitly set.
CompositionEntry::CompositionEntry(const std::string& symbol, const bool massFracMode) : m_symbol(symbol), m_isotope(fourdst::atomic::species.at(symbol)), m_massFracMode(massFracMode) {
setSpecies(symbol);
@@ -81,6 +80,8 @@ namespace fourdst::composition {
if (m_massFracMode) {
return m_massFraction;
}
// Convert from number fraction to mass fraction using: X_i = n_i * A_i / <A>
// where m_relAbundance is n_i * A_i and meanMolarMass is <A>.
return m_relAbundance / meanMolarMass;
}
@@ -94,6 +95,8 @@ namespace fourdst::composition {
double CompositionEntry::number_fraction(const double totalMoles) const {
if (m_massFracMode) {
// Convert from mass fraction to number fraction using: n_i = (X_i / A_i) / sum(X_j / A_j)
// where m_relAbundance is X_i / A_i and totalMoles is sum(X_j / A_j).
return m_relAbundance / totalMoles;
}
return m_numberFraction;
@@ -425,6 +428,7 @@ namespace fourdst::composition {
m_finalized = false;
return false;
}
// After validation, calculate the specific number density (total moles per unit mass).
for (const auto &entry: m_compositions | std::views::values) {
m_specificNumberDensity += entry.rel_abundance();
}
@@ -458,6 +462,7 @@ namespace fourdst::composition {
m_finalized = false;
return false;
}
// After validation, calculate the mean particle mass.
for (const auto &entry: m_compositions | std::views::values) {
m_meanParticleMass += entry.rel_abundance();
}
@@ -477,7 +482,7 @@ namespace fourdst::composition {
}
std::set<std::string> mixedSymbols = other.getRegisteredSymbols();
// Get the union of the two sets
// Get the union of the two sets of symbols to ensure all species are included in the new composition.
mixedSymbols.insert(m_registeredSymbols.begin(), m_registeredSymbols.end());
Composition mixedComposition(mixedSymbols);
@@ -487,6 +492,7 @@ namespace fourdst::composition {
const double thisMassFrac = hasSymbol(symbol) ? getMassFraction(symbol) : 0.0;
otherMassFrac = other.hasSymbol(symbol) ? other.getMassFraction(symbol) : 0.0;
// The mixing formula is a linear interpolation of mass fractions.
double massFraction = fraction * thisMassFrac + otherMassFrac * (1-fraction);
mixedComposition.setMassFraction(symbol, massFraction);
}
@@ -502,7 +508,7 @@ namespace fourdst::composition {
if (!m_compositions.contains(symbol)) {
LOG_ERROR(m_logger, "Symbol {} is not in the composition.", symbol);
std::string currentSymbols;
int count = 0;
size_t count = 0;
for (const auto& sym : m_compositions | std::views::keys) {
currentSymbols += sym;
if (count < m_compositions.size() - 2) {
@@ -622,9 +628,11 @@ namespace fourdst::composition {
// Loop through all registered species in the composition.
for (const auto &val: m_compositions | std::views::values) {
// Sum of (X_i * Z_i / A_i)
zSum += (val.mass_fraction() * val.m_isotope.z())/val.m_isotope.a();
}
// Calculate mean atomic number <Z> = <A> * sum(X_i * Z_i / A_i)
const double mean_A = m_meanParticleMass * zSum;
return mean_A;
}
@@ -763,7 +771,7 @@ namespace fourdst::composition {
std::ostream& operator<<(std::ostream& os, const Composition& composition) {
os << "Composition(finalized: " << (composition.m_finalized ? "true" : "false") << ", " ;
int count = 0;
size_t count = 0;
for (const auto &entry: composition.m_compositions | std::views::values) {
os << entry;
if (count < composition.m_compositions.size() - 1) {