feat(Comoposition-Tracking): updated GridFire to use new, molar-abundance based, version of libcomposition (v2.0.6)
This entailed a major rewrite of the composition handling from each engine and engine view along with the solver and primer. The intent here is to let Compositions be constructed from the same extensive property which the solver tracks internally. This addressed C0 discontinuity issues in the tracked molar abundances of species which were introduced by repeadidly swaping from molar abundance space to mass fraction space and back. This also allowed for a simplification of the primeNetwork method. Specifically the mass borrowing system was dramatically simplified as molar abundances are extensive.
This commit is contained in:
@@ -1,81 +0,0 @@
|
||||
#pragma once
|
||||
#include "fourdst/composition/composition.h"
|
||||
#include "fourdst/composition/atomicSpecies.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
namespace gridfire::utils {
|
||||
inline double massFractionFromMolarAbundanceAndComposition (
|
||||
const fourdst::composition::Composition& composition,
|
||||
const fourdst::atomic::Species& species,
|
||||
const double Yi
|
||||
) {
|
||||
double sum = 0;
|
||||
for (const auto& [symbol, entry] : composition) {
|
||||
if (entry.isotope() == species) {
|
||||
sum += species.mass() * Yi;
|
||||
} else {
|
||||
sum += entry.isotope().mass() * composition.getMolarAbundance(symbol);
|
||||
}
|
||||
}
|
||||
return (species.mass() * Yi) / sum;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Convert a vector of molar abundances into a vector of mass fractions
|
||||
* @param molarAbundances Vector of molar abundances
|
||||
* @param molarMasses Vector of molar masses
|
||||
*
|
||||
* @note The vectors molarAbundances and molarMasses must be parallel. This function does not provide any checks
|
||||
* to ensure that the correct molar mass is being used with the correct molar abundance.
|
||||
* @return A vector of molar masses such that each molar mass < 1 and the sum of all is = 1
|
||||
*/
|
||||
inline std::vector<double> massFractionFromMolarAbundanceAndMolarMass (
|
||||
const std::vector<double>& molarAbundances,
|
||||
const std::vector<double>& molarMasses
|
||||
) noexcept {
|
||||
assert(molarMasses.size() == molarAbundances.size());
|
||||
assert(!molarMasses.empty());
|
||||
|
||||
double totalMass = 0;
|
||||
std::vector<double> masses;
|
||||
masses.reserve(molarMasses.size());
|
||||
for (const auto [m, Y] : std::views::zip(molarMasses, molarAbundances)) {
|
||||
const double mass = m * Y;
|
||||
totalMass += mass;
|
||||
masses.push_back(mass);
|
||||
}
|
||||
|
||||
assert(totalMass > 0);
|
||||
|
||||
std::vector<double> massFractions;
|
||||
massFractions.reserve(masses.size());
|
||||
std::ranges::transform(
|
||||
masses,
|
||||
std::back_inserter(massFractions),
|
||||
[&totalMass](const double speciesMass) {
|
||||
const double Xi = speciesMass / totalMass;
|
||||
if (std::abs(Xi) < 1e-16 && Xi < 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return Xi;
|
||||
});
|
||||
|
||||
return massFractions;
|
||||
}
|
||||
|
||||
inline std::vector<double> molarMassVectorFromComposition(
|
||||
const fourdst::composition::Composition& composition
|
||||
) {
|
||||
std::map<fourdst::atomic::Species, double> molarMassMap;
|
||||
for (const auto &entry: composition | std::views::values) {
|
||||
molarMassMap.emplace(entry.isotope(), entry.isotope().mass());
|
||||
}
|
||||
std::vector<double> molarMassVector;
|
||||
molarMassVector.reserve(molarMassMap.size());
|
||||
for (const auto molarMass : molarMassMap | std::views::values) {
|
||||
molarMassVector.push_back(molarMass);
|
||||
}
|
||||
return molarMassVector;
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,50 @@
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <memory>
|
||||
#include <format>
|
||||
#include <print>
|
||||
#include <cstdlib>
|
||||
#include <cwchar>
|
||||
#include <clocale>
|
||||
|
||||
|
||||
|
||||
namespace gridfire::utils {
|
||||
inline size_t visual_width(const std::string& s) {
|
||||
// IMPORTANT: std::setlocale(LC_ALL, "") must be called once in main()
|
||||
// for mbtowc and wcwidth to function correctly with the system's locale.
|
||||
|
||||
size_t width = 0;
|
||||
std::mbtowc(nullptr, 0, 0); // Reset multi-byte state
|
||||
|
||||
const char* p = s.c_str();
|
||||
const char* end = s.c_str() + s.length();
|
||||
|
||||
while (p < end) {
|
||||
wchar_t wc;
|
||||
// Convert the next multi-byte char to a wide char
|
||||
int byte_len = std::mbtowc(&wc, p, end - p);
|
||||
|
||||
if (byte_len <= 0) {
|
||||
// Invalid byte sequence or null char.
|
||||
// Treat as a 1-width '?' and advance by 1 byte to avoid infinite loop.
|
||||
width++;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the visual width of the wide char
|
||||
int char_width = wcwidth(wc);
|
||||
if (char_width != -1) {
|
||||
width += char_width;
|
||||
}
|
||||
// else: char_width == -1 means non-printable/control char; treat as 0 width
|
||||
|
||||
p += byte_len; // Advance by the number of bytes consumed
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
class ColumnBase {
|
||||
public:
|
||||
virtual ~ColumnBase() = default;
|
||||
@@ -117,6 +158,87 @@ namespace gridfire::utils {
|
||||
return table_ss.str();
|
||||
}
|
||||
|
||||
inline void print_table(const std::string& tableName, const std::vector<std::unique_ptr<ColumnBase>>& columns) {
|
||||
// --- 1. Handle Empty Table ---
|
||||
if (columns.empty()) {
|
||||
std::println("{} \n(Table has no columns)\n", tableName);
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 2. Determine dimensions and calculate column widths (using visual_width) ---
|
||||
size_t num_cols = columns.size();
|
||||
size_t num_rows = 0;
|
||||
for (const auto& col : columns) {
|
||||
num_rows = std::max(num_rows, col->getRowCount());
|
||||
}
|
||||
|
||||
std::vector<size_t> col_widths(num_cols);
|
||||
for (size_t j = 0; j < num_cols; ++j) {
|
||||
// Start with header width
|
||||
col_widths[j] = visual_width(columns[j]->getHeader());
|
||||
// Find max width in all data cells
|
||||
for (size_t i = 0; i < num_rows; ++i) {
|
||||
col_widths[j] = std::max(col_widths[j], visual_width(columns[j]->getCellData(i)));
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3. Print the table using std::print / std::println ---
|
||||
|
||||
// --- Table Title ---
|
||||
// NOLINTNEXTLINE(*-fold-init-type)
|
||||
const size_t total_width = std::accumulate(col_widths.begin(), col_widths.end(), 0UL) + (num_cols * 3) + 1;
|
||||
const size_t title_padding_len = (total_width > visual_width(tableName)) ? (total_width - visual_width(tableName)) / 2 : 0;
|
||||
|
||||
// Print padding, then title
|
||||
std::print("{: <{}}", "", title_padding_len); // Left-aligned empty string "" of width title_padding_len
|
||||
std::println("{}", tableName);
|
||||
|
||||
|
||||
// --- Helper to draw horizontal border ---
|
||||
auto draw_border = [&]() {
|
||||
std::print("+");
|
||||
for (const size_t width : col_widths) {
|
||||
// std::string(width + 2, '-') is still the easiest way to repeat a char
|
||||
std::print("{:-<{}}+", "", width + 2); // Prints '-' repeated (width + 2) times
|
||||
}
|
||||
std::println("");
|
||||
};
|
||||
|
||||
// --- Draw Top Border ---
|
||||
draw_border();
|
||||
|
||||
// --- Helper to print a cell with correct padding ---
|
||||
auto print_cell = [&](const std::string& text, size_t width) {
|
||||
size_t text_width = visual_width(text);
|
||||
size_t padding = (width >= text_width) ? (width - text_width) : 0;
|
||||
// Print text and then the manual padding
|
||||
std::print(" {}{: <{}} |", text, "", padding);
|
||||
};
|
||||
|
||||
// --- Draw Header Row ---
|
||||
std::print("|");
|
||||
for (size_t j = 0; j < num_cols; ++j) {
|
||||
print_cell(columns[j]->getHeader(), col_widths[j]);
|
||||
}
|
||||
std::println("");
|
||||
|
||||
// --- Draw Separator ---
|
||||
draw_border();
|
||||
|
||||
// --- Draw Data Rows ---
|
||||
for (size_t i = 0; i < num_rows; ++i) {
|
||||
std::print("|");
|
||||
for (size_t j = 0; j < num_cols; ++j) {
|
||||
print_cell(columns[j]->getCellData(i), col_widths[j]);
|
||||
}
|
||||
std::println("");
|
||||
}
|
||||
|
||||
// --- Draw Bottom Border ---
|
||||
draw_border();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user