fourdst::libcomposition v2.0.1
Robust atomic species information library
Loading...
Searching...
No Matches
composition.cpp
Go to the documentation of this file.
1/* ***********************************************************************
2//
3// Copyright (C) 2025 -- The 4D-STAR Collaboration
4// File Author: Emily Boudreaux
5// Last Modified: October 6, 2025
6//
7// 4DSSE is free software; you can use it and/or modify
8// it under the terms and restrictions the GNU General Library Public
9// License version 3 (GPLv3) as published by the Free Software Foundation.
10//
11// 4DSSE is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14// See the GNU Library General Public License for more details.
15//
16// You should have received a copy of the GNU Library General Public License
17// along with this software; if not, write to the Free Software
18// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19//
20// *********************************************************************** */
21#include "quill/LogMacros.h"
22
23#include <stdexcept>
24#include <unordered_map>
25#include <vector>
26#include <ranges>
27#include <algorithm>
28#include <set>
29#include <string>
30
31
32#include <utility>
33
37
39
40namespace {
41 template<typename A, typename B>
42 std::vector<A> sortVectorBy(
43 std::vector<A> toSort,
44 const std::vector<B>& by
45 ) {
46 std::vector<std::size_t> indices(by.size());
47 for (size_t i = 0; i < indices.size(); i++) {
48 indices[i] = i;
49 }
50
51 std::ranges::sort(indices, [&](size_t a, size_t b) {
52 return by[a] < by[b];
53 });
54
55 std::vector<A> sorted;
56 sorted.reserve(indices.size());
57
58 for (const auto idx: indices) {
59 sorted.push_back(toSort[idx]);
60 }
61
62 return sorted;
63 }
64
65 std::optional<fourdst::atomic::Species> getSpecies(const std::string& symbol) {
66 if (!fourdst::atomic::species.contains(symbol)) {
67 return std::nullopt;
68 }
69 return fourdst::atomic::species.at(symbol);
70 }
71
72 void throw_unknown_symbol(quill::Logger* logger, const std::string& symbol) {
73 LOG_ERROR(logger, "Symbol {} is not a valid species symbol (not in the species database)", symbol);
74 throw fourdst::composition::exceptions::UnknownSymbolError("Symbol " + symbol + " is not a valid species symbol (not in the species database)");
75 }
76
77 void throw_unregistered_symbol(quill::Logger* logger, const std::string& symbol) {
78 LOG_ERROR(logger, "Symbol {} is not registered in the composition.", symbol);
79 throw fourdst::composition::exceptions::UnregisteredSymbolError("Symbol " + symbol + " is not registered in the composition.");
80 }
81}
82
83namespace fourdst::composition {
85 const std::vector<std::string>& symbols
86 ) {
87 for (const auto& symbol : symbols) {
88 registerSymbol(symbol);
89 }
90 }
91
93 const std::set<std::string>& symbols
94 ) {
95 for (const auto& symbol : symbols) {
96 registerSymbol(symbol);
97 }
98 }
99
101 const std::vector<atomic::Species> &species
102 ) {
103 for (const auto& s : species) {
105 }
106 }
107
109 const std::set<atomic::Species> &species
110 ) {
111 for (const auto& s : species) {
113 }
114 }
115
117 const std::vector<std::string>& symbols,
118 const std::vector<double>& molarAbundances
119 ) {
120 if (symbols.size() != molarAbundances.size()) {
121 LOG_CRITICAL(getLogger(), "The number of symbols and molarAbundances must be equal (got {} symbols and {} molarAbundances).", symbols.size(), molarAbundances.size());
122 throw exceptions::InvalidCompositionError("The number of symbols and fractions must be equal. Got " + std::to_string(symbols.size()) + " symbols and " + std::to_string(molarAbundances.size()) + " fractions.");
123 }
124
125 for (const auto &[symbol, y] : std::views::zip(symbols, molarAbundances)) {
126 registerSymbol(symbol);
127 setMolarAbundance(symbol, y);
128 }
129 }
130
132 const std::vector<atomic::Species> &species,
133 const std::vector<double> &molarAbundances
134 ) {
135 if (species.size() != molarAbundances.size()) {
136 LOG_CRITICAL(getLogger(), "The number of species and molarAbundances must be equal (got {} species and {} molarAbundances).", species.size(), molarAbundances.size());
137 throw exceptions::InvalidCompositionError("The number of species and fractions must be equal. Got " + std::to_string(species.size()) + " species and " + std::to_string(molarAbundances.size()) + " fractions.");
138 }
139
140 for (const auto& [s, y] : std::views::zip(species, molarAbundances)) {
142 setMolarAbundance(s, y);
143 }
144 }
145
147 const std::set<std::string> &symbols,
148 const std::vector<double> &molarAbundances
149 ) {
150 if (symbols.size() != molarAbundances.size()) {
151 LOG_CRITICAL(getLogger(), "The number of symbols and molarAbundances must be equal (got {} symbols and {} molarAbundances).", symbols.size(), molarAbundances.size());
152 throw exceptions::InvalidCompositionError("The number of symbols and fractions must be equal. Got " + std::to_string(symbols.size()) + " symbols and " + std::to_string(molarAbundances.size()) + " fractions.");
153 }
154
155 for (const auto& [symbol, y] : std::views::zip(sortVectorBy<std::string>(std::vector<std::string>(symbols.begin(), symbols.end()), molarAbundances), molarAbundances)) {
156 registerSymbol(symbol);
157 setMolarAbundance(symbol, y);
158 }
159 }
160
163 ) {
164 m_registeredSpecies = composition.m_registeredSpecies;
165 m_molarAbundances = composition.m_molarAbundances;
166 }
167
169 const Composition &other
170 ) {
171 if (this != &other) {
174 }
175 return *this;
176 }
177
179 const std::string& symbol
180 ) {
181 const auto result = getSpecies(symbol);
182 if (!result) {
183 throw_unknown_symbol(getLogger(), symbol);
184 }
185
186 registerSpecies(result.value());
187 }
188
190 const std::vector<std::string>& symbols
191 ) {
192 for (const auto& symbol : symbols) {
193 registerSymbol(symbol);
194 }
195 }
196
198 const atomic::Species &species
199 ) noexcept {
200 m_registeredSpecies.insert(species);
201 if (!m_molarAbundances.contains(species)) {
202 m_molarAbundances.emplace(species, 0.0);
203 }
204 }
205
207 const std::vector<atomic::Species> &species
208 ) noexcept {
209 for (const auto& s : species) {
211 }
212 }
213
214 std::set<std::string> Composition::getRegisteredSymbols() const noexcept {
215 std::set<std::string> symbols;
216 for (const auto& species : m_registeredSpecies) {
217 symbols.insert(std::string(species.name()));
218 }
219 return symbols;
220 }
221
222 const std::set<atomic::Species> &Composition::getRegisteredSpecies() const noexcept {
223 return m_registeredSpecies;
224 }
225
226
227 double Composition::getMassFraction(const std::string& symbol) const {
228 const auto species = getSpecies(symbol);
229 if (!species) {
230 throw_unknown_symbol(getLogger(), symbol);
231 }
232 return getMassFraction(species.value());
233 }
234
236 const atomic::Species &species
237 ) const {
238 if (!m_molarAbundances.contains(species)) {
239 throw_unregistered_symbol(getLogger(), std::string(species.name()));
240 }
241 std::map<atomic::Species, double> raw_mass;
242 double totalMass = 0;
243 for (const auto& [sp, y] : m_molarAbundances) {
244 const double contrib = y * sp.mass();
245 totalMass += contrib;
246 raw_mass.emplace(sp, contrib);
247 }
248 return raw_mass.at(species) / totalMass;
249 }
250
251 std::unordered_map<atomic::Species, double> Composition::getMassFraction() const noexcept {
252 std::unordered_map<atomic::Species, double> mass_fractions;
253 for (const auto &species: m_molarAbundances | std::views::keys) {
254 mass_fractions.emplace(species, getMassFraction(species));
255 }
256 return mass_fractions;
257 }
258
259
261 const std::string& symbol
262 ) const {
263 const auto species = getSpecies(symbol);
264 if (!species) {
265 throw_unknown_symbol(getLogger(), symbol);
266 }
267 return getNumberFraction(species.value());
268 }
269
271 const atomic::Species &species
272 ) const {
273 if (!m_molarAbundances.contains(species)) {
274 throw_unregistered_symbol(getLogger(), std::string(species.name()));
275 }
276 double total_moles_per_gram = 0.0;
277 for (const auto &y: m_molarAbundances | std::views::values) {
278 total_moles_per_gram += y;
279 }
280 return m_molarAbundances.at(species) / total_moles_per_gram;
281 }
282
283 std::unordered_map<atomic::Species, double> Composition::getNumberFraction() const noexcept {
284 std::unordered_map<atomic::Species, double> number_fractions;
285 for (const auto &species: m_molarAbundances | std::views::keys) {
286 number_fractions.emplace(species, getNumberFraction(species));
287 }
288 return number_fractions;
289 }
290
292 const std::string &symbol
293 ) const {
294 const auto species = getSpecies(symbol);
295 if (!species) {
296 throw_unknown_symbol(getLogger(), symbol);
297 }
298 return getMolarAbundance(species.value());
299
300 }
301
303 const atomic::Species &species
304 ) const {
305 if (!m_molarAbundances.contains(species)) {
306 throw_unregistered_symbol(getLogger(), std::string(species.name()));
307 }
308 return m_molarAbundances.at(species);
309 }
310
311 double Composition::getMeanParticleMass() const noexcept {
312 std::vector<double> X = getMassFractionVector();
313 double sum = 0.0;
314 for (const auto& [species, x] : std::views::zip(m_registeredSpecies, X)) {
315 sum += x/species.mass();
316 }
317
318 return 1.0 / sum;
319 }
320
321 double Composition::getElectronAbundance() const noexcept {
322 double Ye = 0.0;
323 for (const auto& [species, y] : m_molarAbundances) {
324 Ye += species.z() * y;
325 }
326 return Ye;
327 }
328
329
331 ) const {
332 using namespace fourdst::atomic;
333
334 if (m_cache.canonicalComp.has_value()) {
335 return m_cache.canonicalComp.value(); // Short circuit if we have cached the canonical composition
336 }
337 CanonicalComposition canonicalComposition;
338 const std::set<Species> canonicalH = {H_1, H_2, H_3, H_4, H_5, H_6, H_7};
339 const std::set<Species> canonicalHe = {He_3, He_4, He_5, He_6, He_7, He_8, He_9, He_10};
340
341 for (const auto& symbol : canonicalH) {
342 if (contains(symbol)) {
343 canonicalComposition.X += getMassFraction(symbol);
344 }
345 }
346 for (const auto& symbol : canonicalHe) {
347 if (contains(symbol)) {
348 canonicalComposition.Y += getMassFraction(symbol);
349 }
350 }
351
352 for (const auto& species : m_molarAbundances | std::views::keys) {
353 const bool isHIsotope = canonicalH.contains(species);
354 const bool isHeIsotope = canonicalHe.contains(species);
355
356 if (isHIsotope || isHeIsotope) {
357 continue; // Skip canonical H and He symbols
358 }
359
360 canonicalComposition.Z += getMassFraction(species);
361 }
362
363 // ReSharper disable once CppTooWideScopeInitStatement
364 const double Z = 1.0 - (canonicalComposition.X + canonicalComposition.Y);
365 if (std::abs(Z - canonicalComposition.Z) > 1e-16) {
366 LOG_ERROR(getLogger(), "Validation composition Z (X-Y = {}) is different than canonical composition Z ({}) (∑a_i where a_i != H/He).", Z, canonicalComposition.Z);
367 throw exceptions::InvalidCompositionError("Validation composition Z (X-Y = " + std::to_string(Z) + ") is different than canonical composition Z (" + std::to_string(canonicalComposition.Z) + ") (∑a_i where a_i != H/He).");
368 }
369 m_cache.canonicalComp = canonicalComposition;
370 return canonicalComposition;
371 }
372
373 std::vector<double> Composition::getMassFractionVector() const noexcept {
374 if (m_cache.massFractions.has_value()) {
375 return m_cache.massFractions.value(); // Short circuit if we have cached the mass fractions
376 }
377
378 std::vector<double> massFractionVector;
379 std::vector<double> speciesMass;
380
381 massFractionVector.reserve(m_molarAbundances.size());
382 speciesMass.reserve(m_molarAbundances.size());
383
384 for (const auto &species: m_molarAbundances | std::views::keys) {
385 massFractionVector.push_back(getMassFraction(species));
386 speciesMass.push_back(species.mass());
387 }
388
389 std::vector<double> massFractions = sortVectorBy(massFractionVector, speciesMass);
390 m_cache.massFractions = massFractions; // Cache the result
391 return massFractions;
392
393 }
394
395 std::vector<double> Composition::getNumberFractionVector() const noexcept {
396 if (m_cache.numberFractions.has_value()) {
397 return m_cache.numberFractions.value(); // Short circuit if we have cached the number fractions
398 }
399
400 std::vector<double> numberFractionVector;
401 std::vector<double> speciesMass;
402
403 numberFractionVector.reserve(m_molarAbundances.size());
404 speciesMass.reserve(m_molarAbundances.size());
405
406 for (const auto &species: m_molarAbundances | std::views::keys) {
407 numberFractionVector.push_back(getNumberFraction(species));
408 speciesMass.push_back(species.mass());
409 }
410
411 std::vector<double> numberFractions = sortVectorBy(numberFractionVector, speciesMass);
412 m_cache.numberFractions = numberFractions; // Cache the result
413 return numberFractions;
414 }
415
416 std::vector<double> Composition::getMolarAbundanceVector() const noexcept {
417 if (m_cache.molarAbundances.has_value()) {
418 return m_cache.molarAbundances.value(); // Short circuit if we have cached the molar abundances
419 }
420
421 std::vector<double> molarAbundanceVector;
422 std::vector<double> speciesMass;
423
424 molarAbundanceVector.reserve(m_molarAbundances.size());
425 speciesMass.reserve(m_molarAbundances.size());
426
427 for (const auto &[species, y]: m_molarAbundances) {
428 molarAbundanceVector.push_back(y);
429 speciesMass.push_back(species.mass());
430 }
431
432 std::vector<double> molarAbundances = sortVectorBy(molarAbundanceVector, speciesMass);
433 m_cache.molarAbundances = molarAbundances; // Cache the result
434 return molarAbundances;
435
436 }
437
439 const std::string &symbol
440 ) const {
441 const auto species = getSpecies(symbol);
442 if (!species) {
443 throw_unknown_symbol(getLogger(), symbol);
444 }
445
446 return getSpeciesIndex(species.value());
447 }
448
451 ) const {
452 if (!m_registeredSpecies.contains(species)) {
453 LOG_ERROR(getLogger(), "Species {} is not in the composition.", species.name());
454 throw exceptions::UnregisteredSymbolError("Species " + std::string(species.name()) + " is not in the composition.");
455 }
456 if (m_cache.sortedSpecies.has_value()) {
457 return std::distance(
458 m_cache.sortedSpecies->begin(),
459 std::ranges::find(
460 m_cache.sortedSpecies.value().begin(),
461 m_cache.sortedSpecies.value().end(),
462 species
463 )
464 );
465 }
466
467 std::vector<atomic::Species> speciesVector;
468 std::vector<double> speciesMass;
469
470 speciesVector.reserve(m_molarAbundances.size());
471 speciesMass.reserve(m_molarAbundances.size());
472
473 for (const auto &s: m_registeredSpecies) {
474 speciesVector.emplace_back(s);
475 speciesMass.push_back(s.mass());
476 }
477
478 std::vector<atomic::Species> sortedSpecies = sortVectorBy(speciesVector, speciesMass);
479 m_cache.sortedSpecies = sortedSpecies;
480 return std::distance(sortedSpecies.begin(), std::ranges::find(sortedSpecies, species));
481 }
482
484 const size_t index
485 ) const {
486 if (m_cache.sortedSpecies.has_value()) {
487 return m_cache.sortedSpecies.value().at(index);
488 }
489
490 std::vector<atomic::Species> speciesVector;
491 std::vector<double> speciesMass;
492
493 speciesVector.reserve(m_molarAbundances.size());
494 speciesMass.reserve(m_molarAbundances.size());
495
496 for (const auto &species: m_registeredSpecies) {
497 speciesVector.emplace_back(species);
498 speciesMass.push_back(species.mass());
499 }
500
501 std::vector<atomic::Species> sortedSymbols = sortVectorBy(speciesVector, speciesMass);
502 if (index >= sortedSymbols.size()) {
503 LOG_ERROR(getLogger(), "Index {} is out of range for composition of size {}.", index, sortedSymbols.size());
504 throw std::out_of_range("Index " + std::to_string(index) + " is out of range for composition of size " + std::to_string(sortedSymbols.size()) + ".");
505 }
506 return sortedSymbols.at(index);
507 }
508
511 ) const noexcept {
512 return m_registeredSpecies.contains(species);
513 }
514
516 const std::string &symbol
517 ) const {
518 const auto species = getSpecies(symbol);
519 if (!species) {
520 throw_unknown_symbol(getLogger(), symbol);
521 }
522 return contains(species.value());
523 }
524
525 size_t Composition::size() const noexcept {
526 return m_registeredSpecies.size();
527 }
528
530 const std::string &symbol,
531 const double &molar_abundance
532 ) {
533 const auto species = getSpecies(symbol);
534 if (!species) {
535 throw_unknown_symbol(getLogger(), symbol);
536 }
537
538 setMolarAbundance(species.value(), molar_abundance);
539 }
540
543 const double &molar_abundance
544 ) {
545 if (!m_registeredSpecies.contains(species)) {
546 throw_unregistered_symbol(getLogger(), std::string(species.name()));
547 }
548 if (molar_abundance < 0.0) {
549 LOG_ERROR(getLogger(), "Molar abundance must be non-negative for symbol {}. Currently it is {}.", species.name(), molar_abundance);
550 throw exceptions::InvalidCompositionError("Molar abundance must be non-negative, got " + std::to_string(molar_abundance) + " for symbol " + std::string(species.name()) + ".");
551 }
552 m_molarAbundances.at(species) = molar_abundance;
553 }
554
556 const std::vector<std::string> &symbols,
557 const std::vector<double> &molar_abundances
558 ) {
559 for (const auto& [symbol, y] : std::views::zip(symbols, molar_abundances)) {
560 setMolarAbundance(symbol, y);
561 }
562 }
563
565 const std::vector<atomic::Species> &species,
566 const std::vector<double> &molar_abundances
567 ) {
568 for (const auto& [s, y] : std::views::zip(species, molar_abundances)) {
569 setMolarAbundance(s, y);
570 }
571 }
572
574 const std::set<std::string> &symbols,
575 const std::vector<double> &molar_abundances
576 ) {
577 for (const auto& [symbol, y] : std::views::zip(symbols, molar_abundances)) {
578 setMolarAbundance(symbol, y);
579 }
580 }
581
583 const std::set<atomic::Species> &species,
584 const std::vector<double> &molar_abundances
585 ) {
586 for (const auto& [s, y] : std::views::zip(species, molar_abundances)) {
587 setMolarAbundance(s, y);
588 }
589 }
590
592
593 std::ostream& operator<<(
594 std::ostream& os,
596 ) {
597 os << "Composition(Mass Fractions => [";
598 size_t count = 0;
599 for (const auto &species : composition.m_registeredSpecies) {
600 os << species << ": " << composition.getMassFraction(species);
601 if (count < composition.size() - 1) {
602 os << ", ";
603 }
604 count++;
605 }
606 os << "])";
607 return os;
608 }
609
610} // namespace fourdst::composition
CompositionCache m_cache
Cache for computed properties to avoid redundant calculations.
size_t getSpeciesIndex(const std::string &symbol) const override
get the index in the sorted vector representation for a given symbol
bool contains(const atomic::Species &species) const noexcept override
Checks if a given species is present in the composition.
std::unordered_map< atomic::Species, double > getNumberFraction() const noexcept override
Gets the number fractions of all species in the composition.
Composition()=default
Default constructor.
void setMolarAbundance(const std::string &symbol, const double &molar_abundance)
Sets the molar abundance for a given symbol.
const std::set< atomic::Species > & getRegisteredSpecies() const noexcept override
Get a set of all species that are registered in the composition.
void registerSpecies(const atomic::Species &species) noexcept
Registers a new species by extracting its symbol.
void registerSymbol(const std::string &symbol)
Registers a new symbol for inclusion in the composition.
std::set< std::string > getRegisteredSymbols() const noexcept override
Gets the registered symbols.
std::set< atomic::Species > m_registeredSpecies
Set of registered species in the composition.
static quill::Logger * getLogger()
Gets the logger instance for the Composition class. This is static to ensure that all composition obj...
Composition & operator=(Composition const &other)
Assignment operator.
double getElectronAbundance() const noexcept override
Compute the electron abundance of the composition.
size_t size() const noexcept override
Gets the number of registered species in the composition.
std::unordered_map< atomic::Species, double > getMassFraction() const noexcept override
Gets the mass fractions of all species in the composition.
std::map< atomic::Species, double > m_molarAbundances
Map of species to their molar abundances.
CanonicalComposition getCanonicalComposition() const
Compute the canonical composition (X, Y, Z) of the composition.
std::vector< double > getMolarAbundanceVector() const noexcept override
Get a uniform vector representation of the molar abundances stored in the composition object sorted s...
double getMolarAbundance(const std::string &symbol) const override
Gets the molar abundances of all species in the composition.
std::vector< double > getNumberFractionVector() const noexcept override
Get a uniform vector representation of the number fractions stored in the composition object sorted s...
atomic::Species getSpeciesAtIndex(size_t index) const override
Get the species at a given index in the sorted vector representation.
std::vector< double > getMassFractionVector() const noexcept override
Get a uniform vector representation of the mass fraction stored in the composition object sorted such...
double getMeanParticleMass() const noexcept override
Compute the mean particle mass of the composition.
Exception thrown when a composition is in an invalid or inconsistent state.
Exception thrown when an unknown symbol is encountered.
Exception thrown when a symbol is used that has not been registered.
Contains canonical information about atomic species and elements used by 4D-STAR.
static const Species H_7("H-7", "H", 5, 6, 1, 7, 940.0, "B-", 23062.0, 652.0, "/2+#", "n ?", 7.052749, 1078.0)
static const Species H_2("H-2", "H", 0, 1, 1, 2, 1112.2831, "B-", std::numeric_limits< double >::quiet_NaN(), std::numeric_limits< double >::infinity(), "+*", "S=0.0145 78", 2.014101777844, 1.5e-05)
static const Species H_6("H-6", "H", 4, 5, 1, 6, 961.6395, "B-", 24283.6294, 294.0, "-#", "?;3n ?", 6.044955437, 272.816)
static const Species He_10("He-10", "He", 6, 8, 2, 10, 2995.134, "B-", 16144.5191, 260.0, "+", "n=100", 10.052815306, 99.676)
static const Species He_9("He-9", "He", 5, 7, 2, 9, 3349.038, "B-", 15980.9213, 2.5, "/2(+)", "=100", 9.043946414, 50.259)
static const std::unordered_map< std::string, const Species & > species
Map of species names to their corresponding Species objects.
Definition species.h:3579
static const Species He_8("He-8", "He", 4, 6, 2, 8, 3924.521, "B-", 10663.8784, 119.5, "+", "-=100;B-n=16 1;B-t=0.9 1", 8.033934388, 0.095)
static const Species He_3("He-3", "He", -1, 1, 2, 3, 2572.68044, "B-", -13736.0, std::numeric_limits< double >::infinity(), "/2+*", "S=0.0002 2", 3.01602932197, 6e-05)
static const Species H_1("H-1", "H", -1, 0, 1, 1, 0.0, "B-", std::numeric_limits< double >::quiet_NaN(), std::numeric_limits< double >::infinity(), "/2+*", "S=99.9855 78", 1.007825031898, 1.4e-05)
static const Species H_5("H-5", "H", 3, 4, 1, 5, 1336.3592, "B-", 21661.2131, 86.0, "1/2+)", "n=100", 5.035311492, 96.02)
static const Species He_7("He-7", "He", 3, 5, 2, 7, 4123.0578, "B-", 11166.0229, 2.51, "3/2)-", "=100", 7.027990652, 8.115)
static const Species He_4("He-4", "He", 0, 2, 2, 4, 7073.9156, "B-", -22898.274, std::numeric_limits< double >::infinity(), "+", "S=99.9998 2", 4.00260325413, 0.00016)
static const Species He_5("He-5", "He", 1, 3, 2, 5, 5512.1325, "B-", -447.6529, 602.0, "/2-", "=100", 5.012057224, 21.47)
static const Species H_3("H-3", "H", 1, 2, 1, 3, 2827.2654, "B-", 18.59202, 388789632.0, "/2+*", "-=100", 3.01604928132, 8e-05)
static const Species He_6("He-6", "He", 2, 4, 2, 6, 4878.5199, "B-", 3505.2147, 806.92, "+", "-=100;B-d=0.000278 18", 6.018885889, 0.057)
static const Species H_4("H-4", "H", 2, 3, 1, 4, 1720.4491, "B-", 22196.2131, 139.0, "-", "=100", 4.026431867, 107.354)
Utilities and types for representing and manipulating chemical compositions.
std::ostream & operator<<(std::ostream &os, const Composition &composition)
OVERLOADS.
Represents an atomic species (isotope) with its fundamental physical properties.
std::string_view name() const
Gets the name of the species.
Represents the canonical (X, Y, Z) composition of stellar material.
Definition composition.h:44
double Y
Mass fraction of Helium.
Definition composition.h:46
double X
Mass fraction of Hydrogen.
Definition composition.h:45
double Z
Mass fraction of Metals.
Definition composition.h:47