Introduction
libcomposition is a modern, C++23 library, for the creation, manipulation, and analysis of astrophysical chemical compositions. It provides a robust and type‑safe interface for assembling a set of isotopes together with their molar abundances and for deriving commonly used bulk properties (mass fractions, number fractions, canonical X/Y/Z, mean particle mass, and electron abundance). libcomposition is designed to be tighly integrated into SERiF and related projects such as GridFire.
Key Features
- Type–Safe Species Representation: Strongly typed isotopes (
fourdst::atomic::Species) generated from evaluated nuclear data (AME2020 / NUBASE2020).
- Molar Abundance Core: Stores absolute molar abundances and derives all secondary quantities (mass / number fractions, mean particle mass, electron abundance) on demand, with internal caching.
- Canonical Composition Support: Direct computation of canonical (X: Hydrogen, Y: Helium, Z: Metals) mass fractions via
getCanonicalComposition().
- Convenience Construction: Helper utilities for constructing compositions from a vector or set of mass fractions (
buildCompositionFromMassFractions).
- Deterministic Ordering: Species are always stored and iterated lightest→heaviest (ordering defined by atomic mass) enabling uniform vector interfaces.
- Clear Exception Hierarchy: Explicit error signaling for invalid symbols, unregistered species, and inconsistent input data.
- Meson + pkg-config Integration: Simple build, install, and consumption in external projects.
Installation
libcomposition uses the Meson build system. A C++23 compatible compiler is required.
Build Steps
Setup the build directory:
The first step is to use meson to set up an out of source build. Note that this means that you can have multiple builds configured and cleanly separated!
Compile the library:
meson by default uses ninja to compile so it should be very fast; however, gcc is very slow when compiling the species database so that might take some time (clang tends to be very fast for this).
meson compile -C builddir
Install the library:
This will also install a pkg-config file!
sudo meson install -C builddir
Build Options
You can enable the generation of a pkg-config file during the setup step, which simplifies linking the library in other projects. By default this is true; it can be useful to disable this when using some build system orchestrator (such as meson-python).
# Enable pkg-config file generation
meson setup builddir -Dpkg-config=true
Usage
Below are focused examples illustrating the current API. All examples assume headers are available via pkg-config or your include path.
1. Constructing a Composition from Symbols
#include <iostream>
int main() {
comp.setMolarAbundance("He-4", 3.0);
comp.setMolarAbundance("C-12", 0.25);
double x_h1 = comp.getMassFraction("H-1");
double y_he4 = comp.getNumberFraction("He-4");
auto canon = comp.getCanonicalComposition();
std::cout << "H-1 mass fraction: " << x_h1 << "\n";
std::cout << "He-4 number fraction: " << y_he4 << "\n";
std::cout << canon << "\n";
}
Manages a collection of chemical species and their abundances.
void setMolarAbundance(const std::string &symbol, const double &molar_abundance)
Sets the molar abundance for a given symbol.
Utilities and types for representing and manipulating chemical compositions.
2. Constructing from Strongly Typed Species
#include <iostream>
int main() {
Composition comp(std::vector<Species>{H_1, He_4, O_16});
comp.setMolarAbundance(He_4, 2.5);
comp.setMolarAbundance(O_16, 0.1);
std::cout << "Mean particle mass: " << comp.getMeanParticleMass() << " g/mol\n";
std::cout << "Electron abundance (Ye): " << comp.getElectronAbundance() << "\n";
}
Contains canonical information about atomic species and elements used by 4D-STAR.
3. Building from Mass Fractions (Helper Utility)
#include <iostream>
int main() {
std::vector<std::string> symbols = {"H-1", "He-4", "C-12"};
std::vector<double> mf = {0.70, 0.28, 0.02};
std::cout << canon << "\n";
}
CanonicalComposition getCanonicalComposition() const
Compute the canonical composition (X, Y, Z) of the composition.
Composition buildCompositionFromMassFractions(const std::vector< std::string > &symbols, const std::vector< double > &massFractions)
Build a Composition object from symbols and their corresponding mass fractions.
4. Iterating and Sorted Vector Interfaces
#include <iostream>
int main() {
for (const auto &[sp, y] : comp) {
std::cout << sp << ": molar = " << y << "\n";
}
std::cout << "He-4 index: " << idx_he4 << ", molar abundance at index: " << molarVec[idx_he4] << "\n";
}
size_t getSpeciesIndex(const std::string &symbol) const override
get the index in the sorted vector representation for a given symbol
std::vector< double > getMolarAbundanceVector() const noexcept override
Get a uniform vector representation of the molar abundances stored in the composition object sorted s...
std::vector< double > getMassFractionVector() const noexcept override
Get a uniform vector representation of the mass fraction stored in the composition object sorted such...
5. Accessing Specific Derived Quantities
double getNumberFraction(const std::string &symbol) const override
Gets the number fraction for a given symbol. See the overload for species-based lookup for more detai...
double getElectronAbundance() const noexcept override
Compute the electron abundance of the composition.
std::unordered_map< atomic::Species, double > getMassFraction() const noexcept override
Gets the mass fractions of all species in the composition.
double getMolarAbundance(const std::string &symbol) const override
Gets the molar abundances of all species in the composition.
double getMeanParticleMass() const noexcept override
Compute the mean particle mass of the composition.
6. Exception Handling Examples
#include <iostream>
int main() {
try {
std::cerr <<
"Caught UnknownSymbolError: " << e.
what() <<
"\n";
}
try {
std::cerr <<
"Caught UnregisteredSymbolError: " << e.
what() <<
"\n";
}
try {
std::cerr <<
"Caught InvalidCompositionError: " << e.
what() <<
"\n";
}
try {
std::cerr <<
"Caught InvalidCompositionError: " << e.
what() <<
"\n";
}
}
void registerSymbol(const std::string &symbol)
Registers a new symbol for inclusion in the composition.
const char * what() const noexcept override
Returns the error message.
Exception thrown when a composition is in an invalid or inconsistent state.
const char * what() const noexcept override
Exception thrown when an unknown symbol is encountered.
Exception thrown when a symbol is used that has not been registered.
Possible Exception States
The library surfaces errors through a focused hierarchy in fourdst::composition::exceptions:
| Exception Type | When It Occurs |
UnknownSymbolError | A string symbol does not correspond to any known isotope in the compiled species database. |
UnregisteredSymbolError | A valid species/symbol is used before being registered with a Composition instance. |
InvalidCompositionError | Construction from mass fractions fails validation (sum deviates from unity beyond tolerance) or canonical (X+Y+Z) check fails. |
CompositionError | Base class; may be thrown for generic composition-level issues (e.g. negative abundances via the documented InvalidAbundanceError contract). |
Recommended patterns:
- Validate externally provided symbol lists before calling bulk registration.
- Use species‑based overloads (strongly typed) where possible for slightly lower overhead (no symbol resolution).
- Wrap construction from mass fractions in a try/catch to surface normalization issues early.
Linking and Integration
Linking with pkg-config
If you installed libcomposition with the pkg-config option enabled, you can get the necessary compiler and linker flags easily:
# Get compiler flags (include paths)
pkg-config --cflags fourdst_composition
# Get linker flags (library paths and names)
pkg-config --libs fourdst_composition
Example compilation command:
g++ my_app.cpp $(pkg-config --cflags --libs fourdst_composition) -o my_app
API Reference
For a complete list of all classes, methods, and functions, see the Namespaces and Classes sections of this generated documentation.
Testing Overview
The test suite (GoogleTest) exercises:
- Species database integrity (selected property spot checks).
- Registration and abundance setting (symbols vs species overloads).
- Mass fraction utility construction and validation tolerances.
- Canonical composition correctness (X + Y + Z ≈ 1.0).
- Vector interface ordering and index lookup consistency.
- Exception pathways for unknown/unregistered symbols and invalid compositions.
Use tolerances (e.g. 1e-12–1e-14) when comparing floating‑point derived quantities in custom tests.