docs(ridfire)

Added more documentation, also moved all engine code into
gridfire::engine namespace to be more in line with other parts of teh
code base
This commit is contained in:
2025-11-24 09:07:49 -05:00
parent 15ed7f70b1
commit 9fab4fbfae
64 changed files with 2506 additions and 848 deletions

View File

@@ -5,17 +5,17 @@
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
namespace gridfire::diagnostics {
void report_limiting_species(
const DynamicEngine& engine,
const std::vector<double>& Y_full,
const std::vector<double>& E_full,
namespace gridfire::engine::diagnostics {
std::optional<nlohmann::json> report_limiting_species(
const DynamicEngine &engine,
const std::vector<double> &Y_full,
const std::vector<double> &E_full,
const double relTol,
const double absTol,
const size_t top_n
const size_t top_n,
bool json
) {
struct SpeciesError {
std::string name;
@@ -66,15 +66,21 @@ namespace gridfire::diagnostics {
columns.push_back(std::make_unique<utils::Column<double>>("Abundance", sorted_abundances));
columns.push_back(std::make_unique<utils::Column<double>>("Error", sorted_errors));
std::cout << utils::format_table("Timestep Limiting Species", columns) << std::endl;
if (json) {
return utils::to_json(columns);
}
utils::print_table("Timestep Limiting Species", columns);
return std::nullopt;
}
void inspect_species_balance(
std::optional<nlohmann::json> inspect_species_balance(
const DynamicEngine& engine,
const std::string& species_name,
const fourdst::composition::Composition &comp,
const double T9,
const double rho
const double rho,
bool json
) {
const auto& species_obj = fourdst::atomic::species.at(species_name);
@@ -103,12 +109,18 @@ namespace gridfire::diagnostics {
}
}
nlohmann::json j;
{
std::vector<std::unique_ptr<utils::ColumnBase>> columns;
columns.push_back(std::make_unique<utils::Column<std::string>>("Reaction ID", creation_ids));
columns.push_back(std::make_unique<utils::Column<int>>("Stoichiometry", creation_stoichiometry));
columns.push_back(std::make_unique<utils::Column<double>>("Molar Flow", creation_flows));
std::cout << utils::format_table("Creation Reactions for " + species_name, columns) << std::endl;
if (json) {
j["Creation_Reactions_" + species_name] = utils::to_json(columns);
}
else {
utils::print_table("Creation Reactions for " + species_name, columns);
}
}
{
@@ -116,43 +128,44 @@ namespace gridfire::diagnostics {
columns.push_back(std::make_unique<utils::Column<std::string>>("Reaction ID", destruction_ids));
columns.push_back(std::make_unique<utils::Column<int>>("Stoichiometry", destruction_stoichiometry));
columns.push_back(std::make_unique<utils::Column<double>>("Molar Flow", destruction_flows));
std::cout << utils::format_table("Destruction Reactions for " + species_name, columns) << std::endl;
if (json) {
j["Destruction_Reactions_" + species_name] = utils::to_json(columns);
} else {
utils::print_table("Destruction Reactions for " + species_name, columns);
}
}
std::cout << "--- Balance Summary for " << species_name << " ---" << std::endl;
std::cout << " Total Creation Rate: " << std::scientific << total_creation_flow << " [mol/g/s]" << std::endl;
std::cout << " Total Destruction Rate: " << std::scientific << total_destruction_flow << " [mol/g/s]" << std::endl;
std::cout << " Net dY/dt: " << std::scientific << (total_creation_flow - total_destruction_flow) << std::endl;
std::cout << "-----------------------------------" << std::endl;
std::vector<std::unique_ptr<utils::ColumnBase>> summary_columns;
summary_columns.push_back(std::make_unique<utils::Column<std::string>>("Metric", std::vector<std::string>{
"Total Creation Rate [mol/g/s]",
"Total Destruction Rate [mol/g/s]",
"Net dY/dt [mol/g/s]"
}));
summary_columns.push_back(std::make_unique<utils::Column<double>>("Value", std::vector<double>{
total_creation_flow,
total_destruction_flow,
total_creation_flow - total_destruction_flow
}));
if (json) {
j["Species_Balance_Summary_" + species_name] = utils::to_json(summary_columns);
return j;
}
utils::print_table("Species Balance Summary for " + species_name, summary_columns);
return std::nullopt;
}
void inspect_jacobian_stiffness(
std::optional<nlohmann::json> inspect_jacobian_stiffness(
const DynamicEngine &engine,
const fourdst::composition::Composition &comp,
const double T9,
const double rho
) {
inspect_jacobian_stiffness(engine, comp, T9, rho, false, std::nullopt);
}
void inspect_jacobian_stiffness(
const DynamicEngine& engine,
const fourdst::composition::Composition &comp,
const double T9,
const double rho,
const bool save,
const std::optional<std::string> &filename
const bool json
) {
NetworkJacobian jac = engine.generateJacobianMatrix(comp, T9, rho);
jac = regularize_jacobian(jac, comp);
if (save) {
if (!filename.has_value()) {
throw std::invalid_argument("Filename must be provided when save is true.");
}
jac.to_csv(filename.value());
}
const auto& species_list = engine.getNetworkSpecies();
@@ -172,16 +185,28 @@ namespace gridfire::diagnostics {
}
}
std::cout << "\n--- Jacobian Stiffness Report ---" << std::endl;
if (max_diag_species.has_value()) {
std::cout << " Largest Diagonal Element (d(dYi/dt)/dYi): " << std::scientific << max_diag
<< " for species " << max_diag_species->name() << std::endl;
std::vector<std::unique_ptr<utils::ColumnBase>> jacobian_columns;
jacobian_columns.push_back(std::make_unique<utils::Column<std::string>>("Metric", std::vector<std::string>{
"Largest Diagonal Element (d(dYi/dt)/dYi)",
"Largest Off-Diagonal Element (d(dYi/dt)/dYj)"
}));
jacobian_columns.push_back(std::make_unique<utils::Column<double>>("Value", std::vector<double>{
max_diag,
max_off_diag
}));
jacobian_columns.push_back(std::make_unique<utils::Column<std::string>>("Species", std::vector<std::string>{
max_diag_species.has_value() ? std::string(max_diag_species->name()) : "N/A",
max_off_diag_species.has_value() ?
("d(" + std::string(max_off_diag_species->first.name()) + ")/d(" + std::string(max_off_diag_species->second.name()) + ")")
: "N/A"
}));
if (json) {
nlohmann::json j;
j["Jacobian_Stiffness"] = utils::to_json(jacobian_columns);
return j;
}
if (max_off_diag_species.has_value()) {
std::cout << " Largest Off-Diagonal Element (d(dYi/dt)/dYj): " << std::scientific << max_off_diag
<< " for d(" << max_off_diag_species->first.name()
<< ")/d(" << max_off_diag_species->second.name() << ")" << std::endl;
}
std::cout << "---------------------------------" << std::endl;
utils::print_table("Jacobian Stiffness Diagnostics", jacobian_columns);
return std::nullopt;
}
}

View File

@@ -1,6 +1,6 @@
#include "gridfire/engine/engine_graph.h"
#include "gridfire/reaction/reaction.h"
#include "gridfire/network.h"
#include "gridfire/types/types.h"
#include "gridfire/screening/screening_types.h"
#include "gridfire/engine/procedures/priming.h"
#include "gridfire/partition/partition_ground.h"
@@ -32,7 +32,7 @@
#include "cppad/utility/sparse_rcv.hpp"
namespace gridfire {
namespace gridfire::engine {
GraphEngine::GraphEngine(
const fourdst::composition::Composition &composition,
const BuildDepthType buildDepth
@@ -66,7 +66,7 @@ namespace gridfire {
syncInternalMaps();
}
std::expected<StepDerivatives<double>, expectations::StaleEngineError> GraphEngine::calculateRHSAndEnergy(
std::expected<StepDerivatives<double>, EngineStatus> GraphEngine::calculateRHSAndEnergy(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -74,17 +74,17 @@ namespace gridfire {
return calculateRHSAndEnergy(comp, T9, rho, m_reactions);
}
std::expected<StepDerivatives<double>, expectations::StaleEngineError> GraphEngine::calculateRHSAndEnergy(
std::expected<StepDerivatives<double>, EngineStatus> GraphEngine::calculateRHSAndEnergy(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho,
const reaction::ReactionSet &activeReactions
) const {
LOG_TRACE_L2(m_logger, "Calculating RHS and Energy in GraphEngine at T9 = {}, rho = {}.", T9, rho);
LOG_TRACE_L3(m_logger, "Calculating RHS and Energy in GraphEngine at T9 = {}, rho = {}.", T9, rho);
const double Ye = comp.getElectronAbundance();
const double mue = 0.0; // TODO: Remove
if (m_usePrecomputation) {
LOG_TRACE_L2(m_logger, "Using precomputation for reaction rates in GraphEngine calculateRHSAndEnergy.");
LOG_TRACE_L3(m_logger, "Using precomputation for reaction rates in GraphEngine calculateRHSAndEnergy.");
std::vector<double> bare_rates;
std::vector<double> bare_reverse_rates;
bare_rates.reserve(activeReactions.size());
@@ -98,7 +98,7 @@ namespace gridfire {
}
}
LOG_TRACE_L2(m_logger, "Precomputed {} forward and {} reverse reaction rates for active reactions.", bare_rates.size(), bare_reverse_rates.size());
LOG_TRACE_L3(m_logger, "Precomputed {} forward and {} reverse reaction rates for active reactions.", bare_rates.size(), bare_reverse_rates.size());
// --- The public facing interface can always use the precomputed version since taping is done internally ---
return calculateAllDerivativesUsingPrecomputation(comp, bare_rates, bare_reverse_rates, T9, rho, activeReactions);
@@ -543,6 +543,15 @@ namespace gridfire {
fullNetIn.temperature = netIn.temperature;
fullNetIn.density = netIn.density;
// Short circuit path if already primed
// if (m_has_been_primed) {
// PrimingReport report;
// report.primedComposition = composition;
// report.success = true;
// report.status = PrimingReportStatus::ALREADY_PRIMED;
// return report;
// }
std::optional<std::vector<reaction::ReactionType>> reactionTypesToIgnore = std::nullopt;
if (!m_useReverseReactions) {
reactionTypesToIgnore = {reaction::ReactionType::WEAK};
@@ -550,6 +559,7 @@ namespace gridfire {
auto primingReport = primeNetwork(fullNetIn, *this, reactionTypesToIgnore);
m_has_been_primed = true;
return primingReport;
}
@@ -603,7 +613,7 @@ namespace gridfire {
const double rho,
const reaction::ReactionSet &activeReactions
) const {
LOG_TRACE_L2(m_logger, "Computing screening factors for {} active reactions.", activeReactions.size());
LOG_TRACE_L3(m_logger, "Computing screening factors for {} active reactions.", activeReactions.size());
// --- Calculate screening factors ---
const std::vector<double> screeningFactors = m_screeningModel->calculateScreeningFactors(
activeReactions,
@@ -636,6 +646,11 @@ namespace gridfire {
forwardAbundanceProduct = 0.0;
break; // No need to continue if one of the reactants has zero abundance
}
double factor = std::pow(comp.getMolarAbundance(reactant), power);
if (!std::isfinite(factor)) {
LOG_CRITICAL(m_logger, "Non-finite factor encountered in forward abundance product for reaction '{}'. Check input abundances for validity.", reaction->id());
throw exceptions::BadRHSEngineError("Non-finite factor encountered in forward abundance product.");
}
forwardAbundanceProduct *= std::pow(comp.getMolarAbundance(reactant), power);
}
@@ -652,7 +667,10 @@ namespace gridfire {
precomputedReaction.symmetry_factor *
forwardAbundanceProduct *
std::pow(rho, numReactants > 1 ? static_cast<double>(numReactants) - 1 : 0.0);
if (!std::isfinite(forwardMolarReactionFlow)) {
LOG_CRITICAL(m_logger, "Non-finite forward molar reaction flow computed for reaction '{}'. Check input abundances and rates for validity.", reaction->id());
throw exceptions::BadRHSEngineError("Non-finite forward molar reaction flow computed.");
}
// --- Reverse reaction flow ---
// Only do this is the reaction has a non-zero reverse symmetry factor (i.e. is reversible)
@@ -678,7 +696,7 @@ namespace gridfire {
reactionCounter++;
}
LOG_TRACE_L2(m_logger, "Computed {} molar reaction flows for active reactions. Assembling these into RHS", molarReactionFlows.size());
LOG_TRACE_L3(m_logger, "Computed {} molar reaction flows for active reactions. Assembling these into RHS", molarReactionFlows.size());
// --- Assemble molar abundance derivatives ---
StepDerivatives<double> result;
@@ -860,10 +878,6 @@ namespace gridfire {
for (size_t j = 0; j < numSpecies; ++j) {
double value = dotY[i * (numSpecies + 2) + j];
if (std::abs(value) > MIN_JACOBIAN_THRESHOLD || i == j) { // Always keep diagonal elements to avoid pathological stiffness
if (i == j && value == 0) {
LOG_WARNING(m_logger, "While generating the Jacobian matrix, a zero diagonal element was encountered at index ({}, {}) (species: {}, abundance: {}). This may lead to numerical instability. Setting to -1 to avoid singularity", i, j, m_networkSpecies[i].name(), adInput[i]);
// value = -1.0;
}
triplets.emplace_back(i, j, value);
}
}
@@ -966,7 +980,7 @@ namespace gridfire {
CppAD::sparse_rcv<std::vector<size_t>, std::vector<double>> jac_subset(CppAD_sparsity_pattern);
// PERF: one of *the* most pressing things that needs to be done is remove the nead for this call every
// PERF: one of *the* most pressing things that needs to be done is remove the need for this call every
// time the jacobian is needed since coloring is expensive and we are throwing away the caching
// power of CppAD by clearing the work vector each time. We do this since we make a new subset every
// time. However, a better solution would be to make the subset stateful so it only changes if the requested
@@ -1100,7 +1114,7 @@ namespace gridfire {
LOG_TRACE_L1(m_logger, "Successfully exported network graph to {}", filename);
}
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesTimescales(
std::expected<std::unordered_map<fourdst::atomic::Species, double>, EngineStatus> GraphEngine::getSpeciesTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -1108,7 +1122,7 @@ namespace gridfire {
return getSpeciesTimescales(comp, T9, rho, m_reactions);
}
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesTimescales(
std::expected<std::unordered_map<fourdst::atomic::Species, double>, EngineStatus> GraphEngine::getSpeciesTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho,
@@ -1144,7 +1158,7 @@ namespace gridfire {
return speciesTimescales;
}
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesDestructionTimescales(
std::expected<std::unordered_map<fourdst::atomic::Species, double>, EngineStatus> GraphEngine::getSpeciesDestructionTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -1152,7 +1166,7 @@ namespace gridfire {
return getSpeciesDestructionTimescales(comp, T9, rho, m_reactions);
}
std::expected<std::unordered_map<fourdst::atomic::Species, double>, expectations::StaleEngineError> GraphEngine::getSpeciesDestructionTimescales(
std::expected<std::unordered_map<fourdst::atomic::Species, double>, EngineStatus> GraphEngine::getSpeciesDestructionTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho,

View File

@@ -19,6 +19,11 @@
#include "quill/LogMacros.h"
namespace {
// Simple heuristic to check if a reaclib reaction is a strong or weak reaction
/* A weak reaction is defined here as one where:
- The number of reactants is equal to the number of products
- There is only one reactant and one product
- The mass number (A) of the reactant is equal to the mass number (A) of the product
*/
bool reaclib_reaction_is_weak(const gridfire::reaction::Reaction& reaction) {
const std::vector<fourdst::atomic::Species>& reactants = reaction.reactants();
const std::vector<fourdst::atomic::Species>& products = reaction.products();
@@ -41,10 +46,10 @@ namespace {
gridfire::reaction::ReactionSet register_weak_reactions(
const gridfire::rates::weak::WeakRateInterpolator &weakInterpolator,
const gridfire::NetworkConstructionFlags reactionTypes
const gridfire::engine::NetworkConstructionFlags reactionTypes
) {
gridfire::reaction::ReactionSet weak_reaction_pool;
if (!has_flag(reactionTypes, gridfire::NetworkConstructionFlags::WRL_WEAK)) {
if (!has_flag(reactionTypes, gridfire::engine::NetworkConstructionFlags::WRL_WEAK)) {
return weak_reaction_pool;
}
@@ -58,7 +63,7 @@ namespace {
parent_species.z() - 1
);
if (downProduct.has_value()) { // Only add the reaction if the Species map contains the product
if (has_flag(reactionTypes, gridfire::NetworkConstructionFlags::BETA_PLUS)) {
if (has_flag(reactionTypes, gridfire::engine::NetworkConstructionFlags::BETA_PLUS)) {
weak_reaction_pool.add_reaction(
std::make_unique<gridfire::rates::weak::WeakReaction>(
parent_species,
@@ -67,7 +72,7 @@ namespace {
)
);
}
if (has_flag(reactionTypes, gridfire::NetworkConstructionFlags::ELECTRON_CAPTURE)) {
if (has_flag(reactionTypes, gridfire::engine::NetworkConstructionFlags::ELECTRON_CAPTURE)) {
weak_reaction_pool.add_reaction(
std::make_unique<gridfire::rates::weak::WeakReaction>(
parent_species,
@@ -78,7 +83,7 @@ namespace {
}
}
if (upProduct.has_value()) { // Only add the reaction if the Species map contains the product
if (has_flag(reactionTypes, gridfire::NetworkConstructionFlags::BETA_MINUS)) {
if (has_flag(reactionTypes, gridfire::engine::NetworkConstructionFlags::BETA_MINUS)) {
weak_reaction_pool.add_reaction(
std::make_unique<gridfire::rates::weak::WeakReaction>(
parent_species,
@@ -87,7 +92,7 @@ namespace {
)
);
}
if (has_flag(reactionTypes, gridfire::NetworkConstructionFlags::POSITRON_CAPTURE)) {
if (has_flag(reactionTypes, gridfire::engine::NetworkConstructionFlags::POSITRON_CAPTURE)) {
weak_reaction_pool.add_reaction(
std::make_unique<gridfire::rates::weak::WeakReaction>(
parent_species,
@@ -103,14 +108,14 @@ namespace {
}
gridfire::reaction::ReactionSet register_strong_reactions(
const gridfire::NetworkConstructionFlags reaction_types
const gridfire::engine::NetworkConstructionFlags reaction_types
) {
gridfire::reaction::ReactionSet strong_reaction_pool;
if (has_flag(reaction_types, gridfire::NetworkConstructionFlags::STRONG)) {
if (has_flag(reaction_types, gridfire::engine::NetworkConstructionFlags::STRONG)) {
const auto& allReaclibReactions = gridfire::reaclib::get_all_reaclib_reactions();
for (const auto& reaction : allReaclibReactions) {
const bool isWeakReaction = reaclib_reaction_is_weak(*reaction);
const bool okayToUseReaclibWeakReaction = has_flag(reaction_types, gridfire::NetworkConstructionFlags::REACLIB_WEAK);
const bool okayToUseReaclibWeakReaction = has_flag(reaction_types, gridfire::engine::NetworkConstructionFlags::REACLIB_WEAK);
const bool reaclibWeakOkay = !isWeakReaction || okayToUseReaclibWeakReaction;
if (!reaction->is_reverse() && reaclibWeakOkay) {
@@ -121,17 +126,17 @@ namespace {
return strong_reaction_pool;
}
bool validate_unique_weak_set(gridfire::NetworkConstructionFlags flag) {
bool validate_unique_weak_set(gridfire::engine::NetworkConstructionFlags flag) {
// This method ensures that weak reactions will only be fetched from either reaclib or the weak reaction library (WRL)
// but not both
std::array<gridfire::NetworkConstructionFlags, 4> WRL_Flags = {
gridfire::NetworkConstructionFlags::BETA_PLUS,
gridfire::NetworkConstructionFlags::ELECTRON_CAPTURE,
gridfire::NetworkConstructionFlags::POSITRON_CAPTURE,
gridfire::NetworkConstructionFlags::BETA_MINUS
std::array<gridfire::engine::NetworkConstructionFlags, 4> WRL_Flags = {
gridfire::engine::NetworkConstructionFlags::BETA_PLUS,
gridfire::engine::NetworkConstructionFlags::ELECTRON_CAPTURE,
gridfire::engine::NetworkConstructionFlags::POSITRON_CAPTURE,
gridfire::engine::NetworkConstructionFlags::BETA_MINUS
};
if (!has_flag(flag, gridfire::NetworkConstructionFlags::REACLIB_WEAK)) {
if (!has_flag(flag, gridfire::engine::NetworkConstructionFlags::REACLIB_WEAK)) {
return true;
}
for (const auto& WRLReactionType : WRL_Flags) {
@@ -143,7 +148,7 @@ namespace {
}
}
namespace gridfire {
namespace gridfire::engine {
using reaction::ReactionSet;
using reaction::Reaction;
using fourdst::atomic::Species;

View File

@@ -6,7 +6,7 @@
#include "gridfire/solver/solver.h"
#include "gridfire/engine/engine_abstract.h"
#include "gridfire/network.h"
#include "gridfire/types/types.h"
#include "gridfire/exceptions/error_solver.h"
#include "fourdst/logging/logging.h"
@@ -15,7 +15,7 @@
#include "quill/LogMacros.h"
namespace gridfire {
namespace gridfire::engine {
using fourdst::composition::Composition;
using fourdst::atomic::Species;
@@ -26,6 +26,11 @@ namespace gridfire {
) {
const auto logger = LogManager::getInstance().getLogger("log");
solver::CVODESolverStrategy integrator(engine);
// Do not need high precision for priming
integrator.set_absTol(1e-3);
integrator.set_relTol(1e-3);
integrator.set_stdout_logging_enabled(false);
NetIn solverInput(netIn);

View File

@@ -10,7 +10,7 @@
#include "quill/LogMacros.h"
namespace gridfire {
namespace gridfire::engine {
NetworkJacobian::NetworkJacobian(
const Eigen::SparseMatrix<double>& jacobianMatrix,
const std::function<fourdst::atomic::Species(size_t)> &indexToSpeciesFunc

View File

@@ -5,13 +5,13 @@
#include <algorithm>
#include "gridfire/network.h"
#include "gridfire/types/types.h"
#include "gridfire/exceptions/error_engine.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
namespace gridfire {
namespace gridfire::engine {
using fourdst::atomic::Species;
AdaptiveEngineView::AdaptiveEngineView(
DynamicEngine &baseEngine
@@ -77,7 +77,7 @@ namespace gridfire {
return m_activeSpecies;
}
std::expected<StepDerivatives<double>, expectations::StaleEngineError> AdaptiveEngineView::calculateRHSAndEnergy(
std::expected<StepDerivatives<double>, EngineStatus> AdaptiveEngineView::calculateRHSAndEnergy(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -205,7 +205,7 @@ namespace gridfire {
throw exceptions::UnableToSetNetworkReactionsError("AdaptiveEngineView does not support setting network reactions directly. Use update() with NetIn instead. Perhaps you meant to call this on the base engine?");
}
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> AdaptiveEngineView::getSpeciesTimescales(
std::expected<std::unordered_map<Species, double>, EngineStatus> AdaptiveEngineView::getSpeciesTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -231,8 +231,7 @@ namespace gridfire {
}
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError>
AdaptiveEngineView::getSpeciesDestructionTimescales(
std::expected<std::unordered_map<Species, double>, EngineStatus> AdaptiveEngineView::getSpeciesDestructionTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -357,7 +356,7 @@ namespace gridfire {
if (!reachable.contains(species)) {
to_vist.push(species);
reachable.insert(species);
LOG_TRACE_L2(m_logger, "Network Connectivity Analysis: Species '{}' is part of the initial fuel.", species.name());
LOG_TRACE_L2(m_logger, "Network Connectivity Analysis: Species {:5} is part of the initial fuel", species.name());
}
}
}
@@ -378,7 +377,7 @@ namespace gridfire {
if (!reachable.contains(product)) {
reachable.insert(product);
new_species_found_in_pass = true;
LOG_TRACE_L2(m_logger, "Network Connectivity Analysis: Species '{}' is reachable via reaction '{}'.", product.name(), reaction->id());
LOG_TRACE_L2(m_logger, "Network Connectivity Analysis: Species {:5} is reachable via reaction {:20}", product.name(), reaction->id());
}
}
}
@@ -397,19 +396,19 @@ namespace gridfire {
LOG_TRACE_L1(m_logger, "Culling reactions based on flow rates...");
const auto relative_culling_threshold = m_config.get<double>("gridfire:AdaptiveEngineView:RelativeCullingThreshold", 1e-75);
double absoluteCullingThreshold = relative_culling_threshold * maxFlow;
LOG_DEBUG(m_logger, "Relative culling threshold: {:0.3E} ({})", relative_culling_threshold, absoluteCullingThreshold);
LOG_DEBUG(m_logger, "Relative culling threshold: {:7.3E} ({:7.3E})", relative_culling_threshold, absoluteCullingThreshold);
std::vector<const reaction::Reaction*> culledReactions;
for (const auto& [reactionPtr, flowRate]: allFlows) {
bool keepReaction = false;
if (flowRate > absoluteCullingThreshold) {
LOG_TRACE_L2(m_logger, "Maintaining reaction '{}' with relative (abs) flow rate: {:0.3E} ({:0.3E} [mol/s])", reactionPtr->id(), flowRate/maxFlow, flowRate);
LOG_TRACE_L2(m_logger, "Maintaining reaction '{:20}' with relative (abs) flow rate: {:7.3E} ({:7.3E} [mol/s])", reactionPtr->id(), flowRate/maxFlow, flowRate);
keepReaction = true;
} else {
bool zero_flow_due_to_reachable_reactants = false;
if (flowRate < 1e-99 && flowRate > 0.0) {
for (const auto& reactant: reactionPtr->reactants()) {
if (comp.getMolarAbundance(reactant) < 1e-99 && reachableSpecies.contains(reactant)) {
LOG_TRACE_L1(m_logger, "Maintaining reaction '{}' with low flow ({:0.3E} [mol/s/g]) due to reachable reactant '{}'.", reactionPtr->id(), flowRate, reactant.name());
LOG_TRACE_L1(m_logger, "Maintaining reaction {:20} with low flow ({:7.3E} [mol/s/g]) due to reachable reactant '{:6}'.", reactionPtr->id(), flowRate, reactant.name());
zero_flow_due_to_reachable_reactants = true;
break;
}
@@ -422,10 +421,10 @@ namespace gridfire {
if (keepReaction) {
culledReactions.push_back(reactionPtr);
} else {
LOG_TRACE_L1(m_logger, "Culling reaction '{}' due to low flow rate or lack of connectivity.", reactionPtr->id());
LOG_TRACE_L1(m_logger, "Culling reaction '{:20}' due to low flow rate or lack of connectivity.", reactionPtr->id());
}
}
LOG_DEBUG(m_logger, "Selected {} (total: {}, culled: {}) reactions based on flow rates.", culledReactions.size(), allFlows.size(), allFlows.size() - culledReactions.size());
LOG_DEBUG(m_logger, "Selected {:5} (total: {:5}, culled: {:5}) reactions based on flow rates.", culledReactions.size(), allFlows.size(), allFlows.size() - culledReactions.size());
return culledReactions;
}
@@ -438,8 +437,9 @@ namespace gridfire {
) const {
const auto result = m_baseEngine.getSpeciesTimescales(comp, T9, rho);
if (!result) {
LOG_ERROR(m_logger, "Failed to get species timescales due to stale engine state.");
throw exceptions::StaleEngineError("Failed to get species timescales");
LOG_CRITICAL(m_logger, "Failed to get species timescales due to base engine failure");
m_logger->flush_log();
throw exceptions::EngineError("Failed to get species timescales due base engine failure");
}
std::unordered_map<Species, double> timescales = result.value();
std::set<Species> onlyProducedSpecies;

View File

@@ -17,7 +17,7 @@
#include "fourdst/composition/exceptions/exceptions_composition.h"
namespace gridfire {
namespace gridfire::engine {
using fourdst::atomic::Species;
DefinedEngineView::DefinedEngineView(
@@ -40,7 +40,7 @@ namespace gridfire {
return m_activeSpeciesVectorCache.value();
}
std::expected<StepDerivatives<double>, expectations::StaleEngineError> DefinedEngineView::calculateRHSAndEnergy(
std::expected<StepDerivatives<double>, EngineStatus> DefinedEngineView::calculateRHSAndEnergy(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -170,7 +170,7 @@ namespace gridfire {
m_activeSpeciesVectorCache = std::nullopt; // Invalidate species vector cache
}
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> DefinedEngineView::getSpeciesTimescales(
std::expected<std::unordered_map<Species, double>, EngineStatus> DefinedEngineView::getSpeciesTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho
@@ -193,7 +193,7 @@ namespace gridfire {
return definedTimescales;
}
std::expected<std::unordered_map<Species, double>, expectations::StaleEngineError> DefinedEngineView::getSpeciesDestructionTimescales(
std::expected<std::unordered_map<Species, double>, EngineStatus> DefinedEngineView::getSpeciesDestructionTimescales(
const fourdst::composition::CompositionAbstract &comp,
const double T9,
const double rho

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
#include <unordered_map>
namespace gridfire {
namespace gridfire::engine {
using fourdst::atomic::species;
NetworkPrimingEngineView::NetworkPrimingEngineView(